home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / programming / utilities / heartbeat.lha / HeartBeat / hb.c < prev    next >
C/C++ Source or Header  |  1994-05-29  |  76KB  |  2,363 lines

  1.  
  2. /*****************************************************************************
  3. * HeartBeat 1.0                                        (C) L. Vanhelsuwé 1992-94
  4. * -------------                                        -------------------------
  5. *
  6. * Written by Laurence Vanhelsuwé in April 1992
  7. *
  8. * HeartBeat is a generic Amiga system call monitor.
  9. * It allows you to monitor a Task's system calls usage or monitor global
  10. * system call activity.
  11. * This program uses the standard Commodore .FD files for all its information
  12. * on available libraries and system calls. This results in a program which
  13. * isn't locked to a certain revision of the Operating System but one that
  14. * evolves with it.
  15. * Additionally, executable size is kept small by not having system call info
  16. * embedded inside the program.
  17. *
  18. * History
  19. * -------
  20. * 06-APR-92: started coding        (goal: loading and parsing of all .fd files)
  21. * 07-APR-92: had a look at gadtools stuff (done most of register requester)
  22. * 08-APR-92:                    (goal: function selection/constant refresh)
  23. * 10-APR-92: modified event loop to more robust global event port system
  24. * 16-APR-92: added new/load/save project options
  25. * 22-APR-92: discovered ASL FileRequest doesn't return full filename! Arghh
  26. * 26-APR-92: added non-ROM vector highlighting (handy for VIRUS detection !)
  27. * 13-JUN-92: added function address printing
  28. * 22-APR-94: Finally cleaned up ASL Filerequester code!
  29. * To Dos:
  30. * -------
  31. * - **!! Ensure monitored libraries don't ever get flushed while we run.
  32. * - Fix currentdir change side-effect
  33. * -
  34. * -
  35. *****************************************************************************/
  36.  
  37. // **!! REQUIRES 2.0 OS !!    (CHECKED AT RUN-TIME)
  38.  
  39.         // Include Amiga specific header files
  40. #include    <exec/execbase.h>
  41. #include    <exec/io.h>
  42. #include    <exec/memory.h>
  43. #include    <exec/nodes.h>
  44. #include    <exec/types.h>
  45.  
  46. #include    <devices/timer.h>
  47.  
  48. #include    <dos/dosextens.h>
  49.  
  50. #include    <intuition/intuition.h>
  51. #include    <intuition/intuitionbase.h>
  52. #include    <intuition/gadgetclass.h>
  53.  
  54. #include    <libraries/asl.h>
  55. #include    <libraries/gadtools.h>
  56.  
  57. #include    <utility/tagitem.h>
  58.  
  59.  
  60.         // Include standard C headers and Lattice specific headers
  61. #include    <stdio.h>
  62. #include    <stdlib.h>
  63. #include    <string.h>
  64. #include    <ctype.h>
  65.  
  66.  
  67.         // Include function prototype definitions
  68.         // Headers coming out of the PROTO directory include #pragmas to use
  69.         // registerized system call calling.
  70.  
  71. #include    <clib/exec_protos.h>
  72. #include    <clib/graphics_protos.h>
  73. #include    <clib/dos_protos.h>
  74. #include    <clib/intuition_protos.h>
  75. #include    <clib/utility_protos.h>
  76. #include    <clib/gadtools_protos.h>
  77. #include    <clib/asl_protos.h>
  78.  
  79. void NewList( struct List *);
  80.  
  81.         // Include Application private headers
  82. #include    "cload_file.h"
  83.  
  84. // All system functions which are currently being tracked have a context
  85. // structure associated with them so that patch stubs can use this to store
  86. // function-specific (local, contextual) information.
  87.  
  88. struct Context {
  89.     ULONG    regvals[16];        // D0..D7, A0..A7
  90.     ULONG    regmasks[16];        // don't care bits for above
  91.     USHORT    freeze;                // freeze on match or just count ?
  92.     USHORT    frozen;                // wedge froze Task TRUE/FALSE
  93.     ULONG    called_cnt;            // each time func gets called this increments
  94.     ULONG    trapped_cnt;        // each time input registers match template
  95.     ULONG    last_called_cnt;    // last value of above (to optimize update)
  96.     ULONG    last_trapped_cnt;    // last value of above (to optimize update)
  97.     APTR    stdvector;            // ptr to normal ROM/RAM routine for this syscall
  98. };
  99.  
  100. // Every library function found in the .fd files gets a structure as follows:
  101.  
  102. struct SysCall {
  103.     struct    Node func_node;        // a node so we can link ya all together
  104.     char    *funcname;            // ptr to name of system call (eg "CurrentDir")
  105.     USHORT    namelen;            // length in bytes of name
  106.     SHORT    func_LVO;            // the _LVO for this function    (eg -$C0)
  107.     struct    Library *parent_lib;// this func belongs to library X
  108.     struct  Context    *ctxt;        // ptr to context struct for patch.
  109. };
  110.  
  111. //-------------------------------------------------------------------------
  112.  
  113. #define        MAX_LIBS        40        // can't cope with more libraries !
  114. #define        MAX_FUNCS        1500    // can't cope with more functions (total)
  115. #define        MAX_PATCHED        72        // can't cope with more PATCHED functions
  116. #define        MAX_FILENAME     512        // maximum absolute filename (LONG PATHS on networks!)
  117.  
  118. #define        POOL_SIZE    (MAX_FUNCS*sizeof(struct SysCall))
  119.  
  120. #define        LF            10
  121.  
  122. #define        REFRESH_FREQ    4    // times a second update call counters
  123.  
  124. // Enumeration type for app_state (application state)
  125.  
  126. #define        FUNCWINDOW    1        // window with function list active
  127. #define        MONWINDOW    2        // window with tracked functions active
  128. #define        REGSWINDOW    3        // register set requester window active
  129. #define        TASKWINDOW    4        // task requester window active
  130.  
  131. #define        WINWIDTH    640        // Need interlace Workbench to open !
  132. #define        WINHEIGHT    340
  133. #define        PANE_X        5        // offset to Gimme00 area.
  134. #define        PANE_Y        12
  135.  
  136. #define        MAX_LABLEN    20        // extra long function names are chopped
  137. #define        MAX_TASKLAB    20        // maximum length of a Task name string in req.
  138.  
  139. #define        CHAR_WIDTH    8        // pixel dimensions for Topaz 80
  140. #define        CHAR_HEIGHT    8
  141.  
  142. // Enumeration type for our scan_state variable
  143.  
  144. #define        NEED_NAME        0    // initial state to grab head like * "dos.library"
  145. #define        NEUTRAL            1    // neutral state to find out what we're looking at.
  146. #define        GET_FUNC        2    // get all other lines
  147. #define        GET_COMMAND        3    // get line with ##cmd
  148.  
  149. #define        ERR_OK            0    // no error occurred
  150. #define        ERR_BADFILE        1    // incorrect file format
  151. #define        ERR_DOSERR        2    // failed to save file
  152. #define        ERR_NOMEM        3    // running out of memory...
  153.  
  154. #define        HB_SIGNATURE    ">>HeartBeat Session dump (C) LVA 1992\n"
  155. //-------------------------------------------------------------------------
  156.  
  157. // Function Prototypes
  158. // -------------------
  159.  
  160. struct    MsgPort *CreateMsgPort    (void);
  161. void    DeleteMsgPort            (struct MsgPort*);
  162.  
  163. // Local function prototypes
  164. //--------------------------
  165.  
  166. void    cleanup                    (void);
  167. void    exit                    (int code);
  168. void    text_to_heap            (struct FileCache *fc);
  169. void    refresh_counters        (void);
  170. void    handle_quit                (void);
  171. void    handle_activation        (void);
  172. void    handle_menuselection    (SHORT menu);
  173. void    handle_keypress            (char key);
  174. void    handle_click            (void);
  175. void    handle_gadgets            (void);
  176. void    append_lib_menus        (void);
  177. void    display_functions        (void);
  178. void    handle_mousemove        (void);
  179. void    unpatch_functions        (void);
  180. void    find_function_info        (void);
  181. void    popup_About_req            (void);
  182. void    reset_counters            (void);
  183. void    kill_taskReq_window        (void);
  184. void    kill_regsReq_window        (void);
  185. void    watch_task                (int index);
  186. void    quick_msg                (char *message, char *exit);
  187. void    strip_lf                (char *str);
  188. void    collect_taskinfo        (struct Node *task);
  189. void    CloseWindowSafely        (struct Window *win);
  190. void    StripIntuiMessages        (struct MsgPort *mp, struct Window *win);
  191. void    init_context            (struct Context *cx);
  192.  
  193. void    fill_box                (int x, int y, int yoffs, int width, struct RastPort*, int pen);
  194. #define    highlight_box(x,y,w)    fill_box(x,y,0,w,rp,3)
  195. #define    erase_box(x,y,w)        fill_box(x,y,0,w,rp,0)
  196. #define    highlight_monbox(x,y,w)    fill_box(x,y,12,w,monrp,3)
  197. #define    erase_monbox(x,y,w)        fill_box(x,y,12,w,monrp,0)
  198.  
  199. BOOL    init_program            (void);
  200. BOOL    process_fd_file            (struct FileCache *fc);
  201. BOOL    popup_funcwindow        (void);
  202. BOOL    add_function            (struct SysCall*);
  203. BOOL    ask_register_info        (char *wintitle, struct Context *ctxt);
  204. BOOL    ask_task                (char *wintitle);
  205.  
  206. int        calc_num_fd_files        (void);
  207. int        load_funclist            (void);
  208. int        save_funclist            (void);
  209.  
  210. char    *get_filename            (char * windowmsg);
  211.  
  212. struct SysCall *find_func        (char *libname, char *funcname);
  213.  
  214. //-------------------------------------------------------------------------
  215. // Global variables
  216. //-----------------
  217. extern struct ExecBase        *SysBase;
  218. extern struct IntuitionBase    *IntuitionBase;
  219.        struct GadToolsBase     *GadToolsBase;    // not part of lc.lib this one
  220.        struct AslBase        *AslBase;
  221. extern struct GfxBase        *GfxBase;
  222.  
  223. extern void WEDGE(void);            // to be copied and patched
  224.  
  225. struct library {
  226.     struct List        funcslist;        // functions for this lib/dev/resource
  227.     char            *libname;        // name of this library/device/resource
  228.     struct Library    *openhandle;    // ret from OpenLibrary/OpenDevice/OpenResource
  229.     int                numfuncs;        // # of entry points
  230. };
  231.  
  232. struct library libs[MAX_LIBS];        // an array to store info on all libs
  233. struct library *curlib=NULL;        // curlib points to the current library
  234.  
  235. struct SysCall *patched_calls[MAX_PATCHED];    // array of ptrs into patched funcs
  236. struct SysCall *selected_syscall;    // -> selected func for register template
  237.  
  238. struct SysCall *node_pool,*pool_base;
  239. struct Context *ctxt_pool;
  240.  
  241. struct Task *SNOOP_TASK;            // Task that's being monitored
  242. struct List taskList;                // global list header for LISTVIEW gadget
  243.  
  244. struct MsgPort *timerport,*IDCMPport;        // our two main IPC ports
  245. struct timerequest timereq;
  246.  
  247. struct Window    *window, *monwindow, *taskwindow, *regswindow;
  248. struct Screen    *screen;
  249. struct RastPort *rp,*monrp,*regsrp;
  250. struct Menu        *menustrip;
  251. struct TextAttr *TAttr;
  252. struct Gadget    *taskReqGads;        // ptr to gadlist for Task Requester window
  253. struct Gadget    *regsReqGads;        // ptr to gadlist for Regs Requester window
  254. void   *vi;                            // global VisualInfo ptr for Workbench Screen
  255.  
  256. struct FileCache fd_caches[MAX_LIBS];    // bookkeeping for cached .fd files
  257. struct FileCache FdDirCache;            // for .fd directory listing file
  258.  
  259. int num_fdfiles;                    // number of .fd libraries        (Constant)
  260. int numlibs;                        // number of accessible libs    (Constant)
  261. int total_funcs;                    // total numer that we know of
  262. int libnum;                            // index into library array (Variable)
  263. int lowlibs;                        // # of libraries in A..I menu
  264. int monitored;                        // # of functions monitored (= patched)
  265. int app_state;                        // state application finds itself in...
  266.  
  267. char filename_buf[MAX_FILENAME];    // large buff to construct abs file names
  268.  
  269. struct RDAres {                        // array for ReadArgs()
  270.     ULONG forceopen;                // force Library to be resident
  271.     ULONG verbose;                    // print lots of debug info.
  272. } options;
  273.  
  274. #define    VERBOSE        options.verbose
  275. #define    FORCEOPEN    options.forceopen
  276.  
  277. SHORT winwidth=WINWIDTH, winheight=WINHEIGHT;
  278. SHORT maxrows;                        // # of rows to print functions
  279. SHORT mousex,mousey;
  280. SHORT msgcode;
  281. SHORT oldboxx = -1, oldboxy = -1;
  282. SHORT oldmonboxy = -1;
  283. SHORT task_num;                        // "remember" variable for Task Req gadget
  284.  
  285. APTR IAddr;                            // ptr to Intuition object (Gadget,..)
  286.  
  287. BOOL quit_me;                        // IDCMP quit request
  288. BOOL menus_exist = FALSE;            // SetMenuStrip() not yet...
  289.  
  290. //-------------------------------------------------------------------------
  291. // A NewWindow struct to open application Windows (re-used many times)
  292. // (Initial values are for main function window only)
  293. //-------------------------------------------------------------------------
  294.  
  295. struct NewWindow nw = {
  296.     0, 16, WINWIDTH, WINHEIGHT,
  297.     255, 255,                        /* Default pens */
  298.  
  299.             // I want to know about following IDCMP Message types
  300. //    IDCMP_CLOSEWINDOW|
  301. //    IDCMP_ACTIVEWINDOW|
  302. //    IDCMP_MENUPICK|
  303. //    IDCMP_MOUSEMOVE|
  304. //    IDCMP_MOUSEBUTTONS|
  305. //    IDCMP_GADGETUP|
  306. //    LISTVIEWIDCMP|
  307.  
  308. // All windows we open get this set of IDCMP bits attached to them.
  309. // Not all windows can generate all those types of msgs though, but that
  310. // doesn't matter (Jimmy).
  311.  
  312. #define    IDCMP_SELECTION (IDCMP_CLOSEWINDOW|\
  313.                          IDCMP_MENUPICK|\
  314.                          IDCMP_MOUSEMOVE|\
  315.                          IDCMP_MOUSEBUTTONS|\
  316.                          IDCMP_GADGETUP|\
  317.                          LISTVIEWIDCMP|\
  318.                          IDCMP_ACTIVEWINDOW)
  319.  
  320.             // BUT we force Intuition to use our own MsgPort so specify 0 here
  321.     0,
  322.  
  323.             // Standard window flags
  324.     WFLG_ACTIVATE|
  325.     WFLG_CLOSEGADGET|
  326.     WFLG_DEPTHGADGET|
  327.     WFLG_DRAGBAR|
  328.     WFLG_REPORTMOUSE,
  329.  
  330.     NULL,                // No gadgets in this window
  331.     (struct Image *) NULL,
  332.     "Amiga HeartBeat 1.0 (written by LVA © April 1992)", // Window title
  333.     (struct Screen *) NULL,
  334.     (struct BitMap *) NULL,
  335.     100, 40,                /* Minimum sizes */
  336.     65535, 65535,            /* Maximum sizes */
  337.     WBENCHSCREEN            /* and put it on the workbench */
  338. };
  339.  
  340. //-------------------------------------------------------------------------
  341. // Menu Layout in compact GadTools format.
  342. //-------------------------------------------------------------------------
  343.  
  344. #define    PROJECT_MENU    0
  345. #define    OPTIONS_MENU    1
  346. #define    LIBS_1_MENU        2
  347. #define    LIBS_2_MENU        3
  348.  
  349. #define     NEW_ITEM         0
  350. #define     LOAD_ITEM         1
  351. #define     SAVE_ITEM         2
  352. #define    DUMMY_ITEM0         3
  353. #define     ABOUT_ITEM         4
  354. #define     QUIT_ITEM         5
  355.  
  356. #define     RESET_ITEM         0
  357. #define     GLOBAL_ITEM     1
  358. #define     TASK_ITEM         2
  359.  
  360. // First empty slot @ offset N
  361. #define    NEWMENU_APPEND    12
  362.  
  363. struct NewMenu mymenus[MAX_LIBS+NEWMENU_APPEND+2]= {
  364.     { NM_TITLE,        "Project",    NULL,    0,0,0},
  365.     { NM_ITEM,        "New",        "N",    0,0,0},    // Kill monitor window
  366.     { NM_ITEM,        "Load Session...",    "L",    0,0,0},    // Load monitor window selection
  367.     { NM_ITEM,        "Save Session...",    "S",    0,0,0},    // Save monitor window selection
  368.     { NM_ITEM,         NM_BARLABEL,NULL,    0,0,0},
  369.     { NM_ITEM,        "About...",    NULL,    0,0,0},
  370.     { NM_ITEM,        "Quit",        "Q",    0,0,0},
  371.  
  372.     { NM_TITLE,        "Options",    NULL,    0,0,0},
  373.     { NM_ITEM,        "Reset counters", "C",0,0,0},
  374.     { NM_ITEM,        "Watch GLOBAL",      "G",0,0,0},
  375.     { NM_ITEM,        "Watch Task.....","T",0,0,0},
  376.  
  377.     { NM_TITLE,        "Libraries A-I",NULL,0,0,0} };
  378.  
  379. //    { NM_END,        NULL,        NULL,    0,0,0} };
  380.  
  381. char version[]="$VER: HeartBeat 1.0 ©LVA (19/MAY/94)";
  382.  
  383. /**************************************************************************
  384. ** Here's the main program.
  385. **
  386. ** Basically:
  387. **    - load and parse all .fd files from the FD: directory.
  388. **    - bring up main function selection window (generate menustrip)
  389. **    - accumulate function selections in the "monitored functions" window
  390. **    - allow users to switch between global and Task snooping, set argument
  391. **      register traps, etc...
  392. **
  393. ** The main event loop needs some explaining:
  394. ** We do a combined Wait() for two sources:
  395. **  1) timer.device timeouts
  396. **  2) Intuition IntuiMessages
  397. ** The timer.device is used instead of INTUITICKS because we want the counters
  398. ** output window to continue updating when another non-HeartBeat window becomes
  399. ** the active one. (INTUITICKS stop when your window is deactivated).
  400. **
  401. ** All windows are hooked into the same message port which in turn generates
  402. ** (and uses) just one signal. That's why the code uses ModifyIDCMP() and
  403. ** messes around with the Window->UserPort field.
  404. **
  405. ** When windows other than the main function window (the window listing all
  406. ** function in a particular library) are opened, input to other windows is
  407. ** not blocked (IDCMP loop still collects from all sources).
  408. ****************************************************************************/
  409.  
  410. void main (void) {
  411.  
  412. struct RDArgs        *rdargs;
  413. struct IntuiMessage *msg;
  414. ULONG msgtype;
  415. ULONG signals,timeout_signal,Intevent_signal;
  416.  
  417.     if ( ((struct Library*)SysBase)->lib_Version < 36) {
  418.         printf("HeartBeat needs AmigaDOS 2.0 (V36+)... Sorry!\n");
  419.         exit(10);
  420.     }
  421.  
  422. // Check command line options.
  423.  
  424.     if (! (rdargs = ReadArgs("FORCE/S,VERBOSE/S", (ULONG*) &options, NULL))) {
  425.         printf("Amiga HeartBeat written by Laurence Vanhelsuwé © April 1992\n");
  426.         printf("HeartBeat is a system call monitoring utility.\n");
  427.         printf("Type HART ? for a full syntax template.\n");
  428.         exit(5);
  429.     }
  430.     FreeArgs(rdargs);
  431.  
  432. // Open libraries, init arrays, memory pools, etc...
  433.     if (!init_program()) exit(50);
  434.  
  435. // From the standard .fd (function definitions) files, get all the info
  436. // about system calls that we need.
  437.     find_function_info();
  438.  
  439. // bring up main function selection window with its menus
  440.     if (!popup_funcwindow()) {
  441.         printf("Failed to open main window (need at least %d*%d Workbench)\n",
  442.                 WINWIDTH, WINHEIGHT+16);
  443.         cleanup();
  444.     }
  445.  
  446.     curlib = &libs[0];            // curlib global for further references
  447.     display_functions();        // 1st library is default
  448.  
  449. // cache the two possible signals that we can receive
  450.     timeout_signal  = 1<<timerport->mp_SigBit;
  451.     Intevent_signal = 1<<IDCMPport->mp_SigBit;
  452.  
  453. // Send initial timeout request to timer.device
  454. // (provides refresh interrupts)
  455.     timereq.tr_time.tv_secs    = 0;
  456.     timereq.tr_time.tv_micro   = 1000000/REFRESH_FREQ;    // MICRO != MILLI
  457.     timereq.tr_node.io_Command = TR_ADDREQUEST;
  458.     SendIO((struct IORequest *) &timereq);                // asynchronous IO !
  459.  
  460.     quit_me = FALSE;        // user hasn't clicked on CLOSE gadget yet...
  461.  
  462.     while (!quit_me) {
  463.  
  464.     // Wait for an Intuition event or a Timer device timeout (or both simult.)
  465.         signals = Wait( Intevent_signal | timeout_signal);
  466.  
  467.         if (signals & timeout_signal) {        // .... ping !
  468.             GetMsg(timerport);                // dequeue msg (is just an ACK)
  469.             timereq.tr_time.tv_secs    = 0;
  470.             timereq.tr_time.tv_micro   = 1000000/REFRESH_FREQ;
  471.             timereq.tr_node.io_Command = TR_ADDREQUEST;
  472.             timereq.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  473.             SendIO((struct IORequest *) &timereq);    // ... pong !
  474.  
  475.             refresh_counters();                // refresh counters window
  476.         }
  477.  
  478.         // For Intuition Messages use the gadtools GetMsg/ReplyMsg variants
  479.         // so that gadtools can intercept gadget clicks which it (and not we)
  480.         // should process (e.g. for CYCLE_KIND or LISTVIEW_KIND gadgets !).
  481.  
  482.         if (signals & Intevent_signal) {
  483.             while (msg = GT_GetIMsg(IDCMPport)) {
  484.  
  485.                   msgtype    = msg->Class;    // copy Message fields and
  486.                 msgcode    = msg->Code;
  487.                 mousex    = msg->MouseX;
  488.                 mousey    = msg->MouseY;
  489.                 IAddr    = msg->IAddress;
  490.  
  491.                 GT_ReplyIMsg(msg);        // reply swiftly
  492.  
  493. #ifdef    DEBUGX
  494. printf("IDCMP MSGTYPE:%8lx (CODE:%8lx) ", msgtype, msgcode);
  495.                 switch (msgtype) {
  496.                     case CLOSEWINDOW:    printf("CLOSEWINDOW\n"); break;
  497.                     case ACTIVEWINDOW:    printf("ACTIVEWINDOW\n"); break;
  498.                     case MENUPICK:        printf("MENUPICK:\n"); break;
  499.                     case MOUSEMOVE:        printf("MOUSEMOVE:\n"); break;
  500.                     case MOUSEBUTTONS:    printf("MOUSEBUTTONS\n"); break;
  501.                     case VANILLAKEY:    printf("VANILLAKEY\n"); break;
  502.                     case GADGETUP:        printf("GADGETUP:\n"); break;
  503.                     case INTUITICKS:    printf("INTUITICKS\n"); break;
  504.                     case REFRESHWINDOW:    printf("REFRESHWINDOW\n"); break;
  505.                     default:            printf("-- UNKNOWN --\n");
  506.                 }
  507. #endif
  508.                 switch (msgtype) {
  509.                     case CLOSEWINDOW:    handle_quit();                    break;
  510.                     case ACTIVEWINDOW:    handle_activation();            break;
  511.                     case MENUPICK:        handle_menuselection(msgcode);    break;
  512.                     case MOUSEMOVE:        handle_mousemove();                break;
  513.                     case MOUSEBUTTONS:    handle_click();                    break;
  514.                     case VANILLAKEY:    handle_keypress( (char) msgcode); break;
  515.                     case GADGETUP:        handle_gadgets();                break;
  516.                     case INTUITICKS:    break;
  517.                     case REFRESHWINDOW:    GT_BeginRefresh((struct Window*)IAddr);
  518.                                         GT_EndRefresh((struct Window*)IAddr, TRUE);
  519.                                         break;
  520.                     default:
  521.                         printf("Unknown IDCMP MSGTYPE:%x (CODE:%x)\n", msgtype, msgcode);
  522.                 }
  523.             }    // WHILE MESSAGES FROM A WINDOW
  524.         }        // IF Intuition event...
  525.     }            // WHILE NOT QUITTING
  526.  
  527.     // At this stage a timout is ALWAYS outstanding so wait for it to come back.
  528.  
  529.     WaitPort(timerport); GetMsg(timerport);
  530.  
  531.     cleanup();        // finally before returning to the CLI...
  532. }
  533.  
  534. //-------------------------------------------------------------------------
  535. // Here follows the various IntuiMessage handlers.
  536. // The handlers themselves further branch to the required logic depending
  537. // on the "state" of HeartBeat. This state is usually directly related to
  538. // which HeartBeat window is currently active.
  539. //
  540. // The IntuiMessage ACTIVEWINDOW therefore is the main cause of state switching.
  541. //-------------------------------------------------------------------------
  542.  
  543.  
  544. //-------------------------------------------------------------------------
  545. // We received a CLOSEWINDOW event. This can come from any of our windows,
  546. // so close requested window only (if main window: signal kill application).
  547. //-------------------------------------------------------------------------
  548.  
  549. void handle_quit(void) {
  550.  
  551.     switch (app_state) {
  552.  
  553.         //-----------------------------------------------------------------
  554.         case FUNCWINDOW:
  555.             if (!monwindow && !taskwindow && !regswindow)
  556.                 quit_me = TRUE;
  557.             break;
  558.  
  559.         //-----------------------------------------------------------------
  560.         case MONWINDOW:
  561.             unpatch_functions();        // unpatch from system !
  562.  
  563.             CloseWindowSafely(monwindow); monwindow = NULL;
  564.  
  565.             if (curlib) display_functions();    // refresh func names list
  566.  
  567.             // app_state = FUNCWINDOW; break;
  568.             ActivateWindow(window);        // this is safer way to achieve same
  569.             break;
  570.  
  571.         //-----------------------------------------------------------------
  572.         case REGSWINDOW:
  573.             kill_regsReq_window();        // done with window: get rid of it
  574.  
  575.             //    app_state = FUNCWINDOW;    // revert to neutral state
  576.             ActivateWindow(window);        // this is safer way to achieve same
  577.             break;
  578.  
  579.         //-----------------------------------------------------------------
  580.         case TASKWINDOW:
  581.             kill_taskReq_window();        // done with window: get rid of it
  582.  
  583.             //    app_state = FUNCWINDOW;    // revert to neutral state
  584.             ActivateWindow(window);        // this is safer way to achieve same
  585.             break;
  586.  
  587.         //-----------------------------------------------------------------
  588.         default: printf("QUIT BUG: appi in unknown state %d\n", app_state);
  589.     }
  590. }
  591. //-------------------------------------------------------------------------
  592. // An ACTIVEWINDOW event has arrived at our main IDCMP comms port.
  593. // To aid in determining which Gadgets get clicked or which window receives
  594. // a mouse click, we track which window is currently the actived one.
  595. //-------------------------------------------------------------------------
  596. void handle_activation(void) {
  597.  
  598.     switch (app_state) {
  599.  
  600.         case FUNCWINDOW:
  601.         case MONWINDOW:
  602.         case TASKWINDOW:
  603.         case REGSWINDOW:
  604.             if (IAddr == (APTR) window)        { app_state = FUNCWINDOW;} else
  605.             if (IAddr == (APTR) monwindow)    { app_state = MONWINDOW; } else
  606.             if (IAddr == (APTR) taskwindow) { app_state = TASKWINDOW;} else
  607.             if (IAddr == (APTR) regswindow) { app_state = REGSWINDOW;}
  608.             break;
  609.  
  610.         default: printf("ACTIV BUG: appi in unknown state %d\n", app_state);
  611.     }
  612. }
  613. //-------------------------------------------------------------------------
  614. // A MENUPICK event has arrived. Only the main function window can generate
  615. // this, but other windows might also be around so watch out for that.
  616. //-------------------------------------------------------------------------
  617. void handle_menuselection(SHORT menu) {
  618.  
  619. int library;
  620. int err;
  621.  
  622.     switch (MENUNUM(menu)) {
  623.         //----------------------------------------------------------------
  624.         case PROJECT_MENU:
  625.             switch (ITEMNUM(menu)) {
  626.                 //--------------------------------------------------------
  627.                 case NEW_ITEM:
  628.                     if (!monwindow) break;        // only if monitor window exists
  629.  
  630.                     unpatch_functions();        // unpatch from system !
  631.                     CloseWindowSafely(monwindow); monwindow = NULL;
  632.  
  633.                     break;
  634.                 //--------------------------------------------------------
  635.                 case LOAD_ITEM:
  636.                     err = load_funclist();
  637.                     switch (err) {
  638.                         case ERR_OK:
  639.                             break;
  640.                         case ERR_BADFILE:
  641.                             quick_msg("Your selected file isn't a HeartBeat file!","Oopps..");
  642.                             break;
  643.                         case ERR_DOSERR:
  644.                             quick_msg("Could not open your file!","Hmmm..");
  645.                             break;
  646.                         default:
  647.                             quick_msg("**!! UNKNOWN ERROR IN LOAD_ITEM","arggh..");
  648.                             break;
  649.                     }
  650.                     break;
  651.                 //--------------------------------------------------------
  652.                 case SAVE_ITEM:
  653.                     if (monwindow) {
  654.                         err = save_funclist();
  655.                         switch (err) {
  656.                             case ERR_OK:
  657.                                 break;
  658.                             case ERR_DOSERR:
  659.                                 quick_msg("Couldn't save session!","Pitty");
  660.                                 break;
  661.                             default:
  662.                                 quick_msg("**!! UNKNOWN ERROR IN LOAD_ITEM","arggh..");
  663.                                 break;
  664.                         }
  665.                     } else {
  666.                         quick_msg("No monitoring session to save!","Sorry..");
  667.                     }
  668.                     break;
  669.                 //--------------------------------------------------------
  670.                 case ABOUT_ITEM:
  671.                     popup_About_req();
  672.                     break;
  673.                 //--------------------------------------------------------
  674.                 case QUIT_ITEM:
  675.                     if (!monwindow && !taskwindow && !regswindow)
  676.                         quit_me = TRUE;
  677.                     break;
  678.             }
  679.             break;
  680.         //----------------------------------------------------------------
  681.         case OPTIONS_MENU:
  682.             switch (ITEMNUM(menu)) {
  683.                 //--------------------------------------------------------
  684.                 case GLOBAL_ITEM:
  685.                     reset_counters();
  686.                     SNOOP_TASK = NULL;
  687.                     if (monwindow)
  688.                         SetWindowTitles(monwindow,"Monitored functions (GLOBAL)", (char*) -1);
  689.                     break;
  690.                 //--------------------------------------------------------
  691.                 case TASK_ITEM:
  692.                     if (!taskwindow) {
  693.                         // pop up window with list of Tasks. User selection
  694.                         // will come to us via standard gadget clicks, not
  695.                         // here !
  696.                         ask_task("Please select any Task.");
  697.                     } else {
  698.                         WindowToFront(taskwindow);
  699.                         ActivateWindow(taskwindow);
  700.                     }
  701.                     break;
  702.                 //--------------------------------------------------------
  703.                 case RESET_ITEM:
  704.                     reset_counters();
  705.                     break;
  706.             }
  707.             break;
  708.         //----------------------------------------------------------------
  709.         case LIBS_1_MENU:
  710.             library = ITEMNUM(menu);
  711.             curlib = &libs[library];    // curlib global for further references
  712.             display_functions();
  713.             break;
  714.         //----------------------------------------------------------------
  715.         case LIBS_2_MENU:
  716.             library = ITEMNUM(menu) + lowlibs;
  717.             curlib = &libs[library];
  718.             display_functions();
  719.             break;
  720.     }
  721. }
  722. //-------------------------------------------------------------------------
  723. // If mouse points at a new function, de-highlight old box and highlight new
  724. // one.
  725. // This has the effect of a cursor over the available functions.
  726. //-------------------------------------------------------------------------
  727.  
  728. void handle_mousemove(void) {
  729. SHORT boxx,boxy,monboxy;
  730.  
  731.     switch (app_state) {
  732.         //----------------------------------------------------------------
  733.         case MONWINDOW:
  734.             monboxy = (mousey-PANE_Y-1-12)/CHAR_HEIGHT;
  735.             // If mouse moved out of previous box area...
  736.             if (monboxy != oldmonboxy) {
  737.  
  738.                 // restrict legal box movements!
  739.  
  740.                 if ( monboxy >= 0 && monboxy < monitored ) {
  741.                     if (oldmonboxy != -1) {
  742.                         erase_monbox(0,oldmonboxy,(MAX_LABLEN+25)*CHAR_WIDTH);
  743.                     }
  744.  
  745.                     highlight_monbox(0,monboxy,(MAX_LABLEN+25)*CHAR_WIDTH);
  746.                     oldmonboxy = monboxy;
  747.                 }
  748.             }
  749.             break;
  750.         //----------------------------------------------------------------
  751.         case FUNCWINDOW:
  752.  
  753.             boxx = (mousex-PANE_X)/(MAX_LABLEN*CHAR_WIDTH);
  754.             boxy = (mousey-PANE_Y-1)/CHAR_HEIGHT;
  755.  
  756.             // If mouse moved out of previous box area...
  757.             if (boxx != oldboxx || boxy != oldboxy) {
  758.  
  759.                 if (boxx >= 0        &&            // restrict legal box movements!
  760.                     boxy >= 0        &&
  761.                     boxy < maxrows    &&
  762.                     (boxy + maxrows*boxx) < curlib->numfuncs) {
  763.  
  764.                         if (oldboxx != -1) {
  765.                             erase_box(oldboxx,oldboxy,(MAX_LABLEN*CHAR_WIDTH)-10);
  766.                         }
  767.  
  768.                         highlight_box(boxx,boxy, (MAX_LABLEN*CHAR_WIDTH)-10 );
  769.                         oldboxx = boxx;    oldboxy = boxy;
  770.                 }
  771.             }
  772.             break;
  773.         //----------------------------------------------------------------
  774.     }
  775. }
  776. //-------------------------------------------------------------------------
  777. // A MOUSEBUTTON event arrived.
  778. //
  779. // If in function window then add selected function to list of traced ones if
  780. // not already being traced.
  781. //
  782. // If in monitored functions window, see comment further down.
  783. //-------------------------------------------------------------------------
  784. void handle_click (void) {
  785.  
  786.     if (msgcode & 0x80) return;            // don't bother with release clicks
  787.  
  788.     switch (app_state) {
  789.  
  790.         //----------------------------------------------------------------
  791.         case FUNCWINDOW:
  792.  
  793.             if (oldboxx != -1) {        // don't select invalid funcs
  794.  
  795.             struct SysCall *syscall;    // define some very local variables
  796.             int funcnum;
  797.  
  798.                 funcnum = oldboxy + maxrows * oldboxx;
  799.                 syscall = ((struct SysCall *)curlib->funcslist.lh_Head) + funcnum;
  800.  
  801.                 // add function to list of tracked ones
  802.                 add_function(syscall);
  803.  
  804.                 // Once at least one function is being traced,
  805.                 // the option menu items become available
  806.                 OnMenu(window, FULLMENUNUM(OPTIONS_MENU,NOITEM,NOSUB));
  807.             }
  808.             break;
  809.  
  810.         //----------------------------------------------------------------
  811.         // A click in the monitoring window can mean two things:
  812.         //    a) user wants to define the input registers for a match
  813.         //    b) if the selected function has trapped and frozen its Task
  814.         //        un-freeze task by sending it a Signal()
  815.         //----------------------------------------------------------------
  816.  
  817.         case MONWINDOW:
  818.  
  819.             if (oldmonboxy != -1) {        // don't accept invalid funcs
  820.  
  821.             struct Context *cx;
  822.  
  823.                 cx = patched_calls[oldmonboxy]->ctxt;
  824.                 if (SNOOP_TASK && cx->frozen) {
  825.  
  826.                     Signal(SNOOP_TASK, 1<<24);    // de-freeze Task
  827.  
  828.                 } else {
  829.  
  830.                     selected_syscall = patched_calls[oldmonboxy];
  831.                     if (!regswindow) {
  832.  
  833.                         // pop up window with all 680x0 registers. User changes
  834.                         // will come to us via standard gadget clicks, not here !
  835.  
  836.                         ask_register_info("Define Arg Registers", selected_syscall->ctxt);
  837.  
  838.                     } else {
  839.                         WindowToFront(regswindow);
  840.                         ActivateWindow(regswindow);
  841.                     }
  842.                 }
  843.             }
  844.             break;
  845.         //----------------------------------------------------------------
  846.         case TASKWINDOW:
  847.         case REGSWINDOW: break;
  848.  
  849.         default:
  850.             printf("CLICK BUG: appi in unknown state %d\n", app_state);
  851.     }
  852. }
  853. //-------------------------------------------------------------------------
  854. // **!! At this point HartBeat doesn't use individual key presses.
  855. //-------------------------------------------------------------------------
  856. void handle_keypress(char key) {
  857.     //    printf("Key pressed: %c\n", key);
  858. }
  859. //-------------------------------------------------------------------------
  860. // A GADGETUP event arrived. Meaning any of our Gadgets scattered around
  861. // multiple Windows has been clicked.
  862. //-------------------------------------------------------------------------
  863.  
  864. #define    TSKLST_LIST        0
  865. #define    TSKLST_USE        1
  866. #define    TSKLST_CANCEL    2
  867.  
  868. #define    REGLST_CYCLE    32
  869. #define    REGLST_USE        33
  870. #define    REGLST_CANCEL    34
  871.  
  872. void handle_gadgets(void) {
  873. USHORT gid;
  874.  
  875.     gid = ((struct Gadget*)IAddr)->GadgetID;
  876.  
  877.     switch (app_state) {
  878.         //-----------------------------------------------------------------
  879.         case REGSWINDOW:
  880.             switch (gid) {
  881.                 //---------------------------------------------------------
  882.                 case REGLST_USE: {
  883.                     struct Gadget *gad;
  884.                     struct Context *ctxt;
  885.                     char *str;
  886.                     int regs,val;
  887.  
  888.                     // -> 1st string Gadget (Skip Gadtools "context" gadget)
  889.                     gad = regsReqGads->NextGadget; ctxt = selected_syscall->ctxt;
  890.                     
  891.                     for(regs=0; regs<32; regs++) {
  892.  
  893.                         str = ((struct StringInfo*)gad->SpecialInfo)->Buffer;
  894.  
  895.                         if (*str == '$') {
  896.                             if (!sscanf(str+1,"%lx", &val)) val = -1;
  897.                         } else {
  898.                             if (!sscanf(str,"%ld", &val)) val = -1;
  899.                         }
  900.  
  901.                         if (regs&1)                            // if gadID is odd,
  902.                             ctxt->regmasks[regs>>1] = val;    // it's a mask
  903.                         else                                // else
  904.                             ctxt->regvals[regs>>1] = val;    // it's a register
  905.  
  906.                         gad = gad->NextGadget;            // goto next string gadg
  907.  
  908.                      }    // end of for
  909.                     }    // end of compound statement
  910.  
  911.                         // Fall thru to kill window
  912.                 //---------------------------------------------------------
  913.                 case REGLST_CANCEL:
  914.                     kill_regsReq_window();    // done with window: get rid of it
  915.  
  916.                     //    app_state = FUNCWINDOW;    // revert to neutral state
  917.                     ActivateWindow(window);    // this is safer way to achieve same
  918.                     break;
  919.                 //---------------------------------------------------------
  920.                 case REGLST_CYCLE:
  921.                     selected_syscall->ctxt->freeze = (msgcode==1) ? -1 : 0 ;
  922.                     selected_syscall->ctxt->frozen = FALSE;
  923.                     break;
  924.                 //---------------------------------------------------------
  925.             }
  926.             break;
  927.         //-----------------------------------------------------------------
  928.         case TASKWINDOW:
  929.             switch ( ((struct Gadget*)IAddr)->GadgetID) {
  930.                 //---------------------------------------------------------
  931.                 case TSKLST_LIST:
  932.                     task_num = msgcode;        // register which Task user selected
  933.                     break;
  934.                 //---------------------------------------------------------
  935.                 case TSKLST_USE:
  936.                     watch_task(task_num);    // using previously recorded selection
  937.                     SetWindowTitles(monwindow,"Monitored functions (TASK)", (char*) -1);
  938.                     reset_counters();        // switch to snoop new Task
  939.                         // Fall thru to kill window
  940.                 //---------------------------------------------------------
  941.                 case TSKLST_CANCEL:
  942.                     kill_taskReq_window();    // done with window: get rid of it
  943.  
  944.                     //    app_state = FUNCWINDOW;    // revert to neutral state
  945.                     ActivateWindow(window);    // this is safer way to achieve same
  946.                     break;
  947.             }
  948.             break;
  949.         //-----------------------------------------------------------------
  950.         case FUNCWINDOW:
  951.         case MONWINDOW:
  952.         default: printf("GADGET BUG: appi in unknown state %d\n", app_state);
  953.     }
  954. }
  955. //-------------------------------------------------------------------------
  956. // List all functions of a selected library in neat columns in the main window.
  957. // Display all functions which don't point to ROM in INVERSE VIDEO.
  958. //-------------------------------------------------------------------------
  959.  
  960. void display_functions(void) {
  961.  
  962. int i,len;
  963. struct SysCall *func;
  964. ULONG vector;
  965.  
  966.     SetDrMd(rp,JAM1);                        // normal drawing mode
  967.     SetAPen(rp,0);                            // use background pen to wipe
  968.     RectFill(rp, PANE_X, PANE_Y, winwidth-5, winheight-3); // previous functions off
  969.  
  970.     SetAPen(rp,1);                            // use text pen
  971.     maxrows = (winheight-18)/CHAR_HEIGHT;
  972.  
  973.         // point to first function node
  974.     func = (struct SysCall*) curlib->funcslist.lh_Head;
  975.  
  976.     i = 0;                                    // start index from 0
  977.     while (func->func_node.ln_Succ) {
  978.             // limit label length to fit in column
  979.         len = (func->namelen > MAX_LABLEN ? MAX_LABLEN : func->namelen);
  980.  
  981.         Move(rp, PANE_X +    (i/maxrows)*MAX_LABLEN*CHAR_WIDTH,
  982.                  PANE_Y + 6 +(i%maxrows)*CHAR_HEIGHT);
  983.  
  984.             // find out where function points to currently.
  985.             // if not the ROM then highlight function name.
  986.         vector = *((ULONG*)(((char*)func->parent_lib) + func->func_LVO +2));
  987.         if (vector < 0xF80000 || vector >0xFFFFFC) {
  988.             SetDrMd(rp,INVERSVID);                    // highlight function
  989.             Text(rp, func->funcname, len);
  990.             SetDrMd(rp,JAM1);                        // revert to normal mode
  991.         } else {
  992.             Text(rp, func->funcname, len);
  993.         }
  994.  
  995.         func = (struct SysCall*) func->func_node.ln_Succ;
  996.         i++;
  997.     }
  998.  
  999.     app_state = FUNCWINDOW;                    // functions are now selectable...
  1000.     oldboxx = -1;                            // invalidate last box
  1001. }
  1002. //-------------------------------------------------------------------------
  1003. // User selected the "About..." option in the Project menu.
  1004. // Give him some info.
  1005. //-------------------------------------------------------------------------
  1006. void popup_About_req(void) {
  1007.  
  1008. static struct EasyStruct aboutES = {
  1009.     sizeof (struct EasyStruct),
  1010.     0,
  1011.     "HeartBeat Program Information Broadcast", "\
  1012. HeartBeat allows you to snoop on any Amiga system calls.\n\
  1013. To select functions to be tracked, first select any Library,\n\
  1014. Device or Resource from the Libraries menus and then click\n\
  1015. on any function(s) you wish to snoop on.\n\
  1016. WARNING: Take it easy with Exec... or be punished !\n\
  1017. e.g. SuperVisor(), SumLibrary(), CacheClearU(), ...\n\
  1018. \n\
  1019. HeartBeat was written by Laurence Vanhelsuwé.\n\
  1020. You can contact the author at the following address:\n\
  1021. \n\
  1022. Christinastraat 105\n\
  1023. B-8400 Oostende\n\
  1024. Belgium\n\
  1025. Europe",
  1026.  
  1027.     "Thanks|Great|WILLCO|Yeah|OK",
  1028. };
  1029.  
  1030.     EasyRequest(window, &aboutES, NULL);
  1031. }
  1032. //-------------------------------------------------------------------------
  1033. // User wants to load a previously saved monitoring session.
  1034. //-------------------------------------------------------------------------
  1035. #define    BUFLEN    60                    // size of line buffer
  1036.  
  1037. int load_funclist (void) {
  1038.  
  1039. struct SysCall *scall;
  1040. char libnamebuf[BUFLEN],funcnamebuf[BUFLEN];
  1041. char *fname, *ptr;
  1042. FILE *fhandle;
  1043. BOOL added;
  1044.  
  1045.     // Ask user where to load session information from.
  1046.  
  1047.     fname = get_filename("Session filename to LOAD");
  1048.     if (!fname) return ERR_NOMEM;
  1049.  
  1050.     fhandle = fopen(fname,"r"); if (!fhandle) return ERR_DOSERR;
  1051.  
  1052.     // Check that file is a HeartBeat file.
  1053.     fgets(libnamebuf, BUFLEN, fhandle);
  1054.  
  1055.     if (strcmp(libnamebuf, HB_SIGNATURE)) {
  1056.         fclose(fhandle);
  1057.         return ERR_BADFILE;
  1058.     }
  1059.  
  1060.     // Read in session file until EOF is encountered or until func list is full
  1061.     do {
  1062.         ptr = fgets(libnamebuf ,BUFLEN, fhandle);
  1063.         ptr = fgets(funcnamebuf,BUFLEN, fhandle);
  1064.  
  1065.         if (ptr) {
  1066.             scall = find_func(libnamebuf, funcnamebuf);
  1067.             if (scall) {
  1068.                 added = add_function(scall);
  1069.             } else {
  1070. //                printf("%s, %s NOT VISISBLE !\n", libnamebuf, funcnamebuf);
  1071.             }
  1072.         }
  1073.     } while (ptr && added);
  1074.  
  1075.     fclose(fhandle);
  1076.  
  1077.     // Once at least one function is being traced,
  1078.     // the option menu items can become available
  1079.     OnMenu(window, FULLMENUNUM(OPTIONS_MENU,NOITEM,NOSUB));
  1080.  
  1081.     return ERR_OK;
  1082. }
  1083.  
  1084. //-------------------------------------------------------------------------
  1085. // Check whether a function traced in a previous session is again visible.
  1086. // If so, return its SysCall struct ptr.
  1087. //-------------------------------------------------------------------------
  1088. struct SysCall *find_func( char *libname, char *funcname) {
  1089.  
  1090. struct SysCall *syscall;
  1091.  
  1092.     strip_lf(libname); strip_lf(funcname);
  1093.  
  1094.     for (libnum=0; libnum<numlibs; libnum++) {                // chk all lib slots
  1095.         if (libs[libnum].openhandle) {                        // if loaded..
  1096.             if (!strcmp(libs[libnum].libname, libname)) {    // and same as arg
  1097.                 syscall = (struct SysCall*) libs[libnum].funcslist.lh_Head;
  1098.                 while (syscall->func_node.ln_Succ) {        // traverse func list
  1099.  
  1100.                     if (!strcmp (syscall->funcname, funcname))    // if func exists
  1101.                         return syscall;                        // tell caller
  1102.  
  1103.                     syscall = (struct SysCall*) syscall->func_node.ln_Succ;
  1104.  
  1105.                 }    // while functions on library function list
  1106.             }        // only if same library as argument
  1107.         }            // only for loaded libraries
  1108.     }                // while libraries
  1109.  
  1110.     return NULL;
  1111. }
  1112. //-------------------------------------------------------------------------
  1113. // User wants to save his current monitoring sessions for later.
  1114. //-------------------------------------------------------------------------
  1115. int save_funclist (void) {
  1116.  
  1117. struct SysCall **syscall = patched_calls;    // point to array of SysCall ptrs
  1118.  
  1119. char *fname;
  1120. int i;
  1121. FILE *fhandle;
  1122.  
  1123.     // Ask user where to save session information to.
  1124.  
  1125.     fname = get_filename("Session filename to SAVE");
  1126.     if (!fname) return ERR_NOMEM;
  1127.  
  1128.     // Open file and print file header
  1129.     fhandle = fopen(fname,"w");
  1130.     fprintf(fhandle, HB_SIGNATURE);
  1131.  
  1132.     // Dump session information to file
  1133.     for(i=1; i <= monitored; i++) {
  1134.         fprintf(fhandle, "%s\n", (*syscall)->parent_lib->lib_Node.ln_Name);
  1135.         fprintf(fhandle, "%s\n", (*syscall)->funcname);
  1136.         syscall++;                            // goto next SysCall structure
  1137.     }
  1138.  
  1139.     fclose(fhandle);
  1140.  
  1141.     return ERR_OK;
  1142. }
  1143.  
  1144. //-------------------------------------------------------------------------
  1145. // Generic Filename request.
  1146. //-------------------------------------------------------------------------
  1147. char * get_filename(char * windowmsg) {
  1148.  
  1149. struct FileRequester *fr;
  1150. char *ptr;
  1151. BOOL result;
  1152.  
  1153.     fr = AllocAslRequestTags(ASL_FileRequest, NULL);
  1154.     if (!fr) return NULL;
  1155.  
  1156. // Ask user what filename he wants to use
  1157.  
  1158.     result = AslRequestTags(fr,
  1159. //            ASLFR_TitleText,windowmsg,    // need a newer INCLUDE file : AARRGH
  1160.  
  1161.             ASL_Hail,windowmsg,            // using obsolete version TAG instead **!!
  1162.  
  1163.             NULL);
  1164.  
  1165.     if (!result) return NULL;
  1166.  
  1167.     if (fr->rf_Dir) {        // if there's a directory component..
  1168.  
  1169.         ptr = stpcpy(filename_buf, fr->rf_Dir);        // 1st copy path
  1170.  
  1171.         if (*(ptr-1) != ':')
  1172.             *ptr++ = '/';                            // separate path from file
  1173.  
  1174.         stpcpy(ptr, fr->rf_File);                    // then append filename
  1175.  
  1176.     } else {
  1177.         strcpy(filename_buf, fr->rf_File);
  1178.     }
  1179.  
  1180.     FreeAslRequest(fr);
  1181.  
  1182.     return filename_buf;
  1183. }
  1184. //-------------------------------------------------------------------------
  1185. // This is a generic routine to bring up small message requesters.
  1186. //-------------------------------------------------------------------------
  1187. void quick_msg (char *message, char *exit) {
  1188.  
  1189. struct EasyStruct quickES;
  1190.  
  1191.     quickES.es_StructSize    = sizeof (struct EasyStruct);
  1192.     quickES.es_Flags        = 0;
  1193.     quickES.es_Title        = "HeartBeat says...";
  1194.     quickES.es_TextFormat    = message;
  1195.     quickES.es_GadgetFormat    = exit;
  1196.  
  1197.     EasyRequest(window, &quickES, NULL);
  1198. }
  1199. //-------------------------------------------------------------------------
  1200. // Most Amiga systems should have a directory full of ".fd" files containing
  1201. // Amiga system function definitions.
  1202. // Go and find this directory and extract as much possible information from
  1203. // these files.
  1204. //
  1205. // An example of real .FD file follows
  1206. /*
  1207.  
  1208. * "battclock.resource"
  1209. ##base _BattClockBase
  1210. ##bias 6
  1211. ##public
  1212. ResetBattClock()()
  1213. ReadBattClock()()
  1214. WriteBattClock(time)(d0)
  1215. ##private
  1216. battclockPrivate1()()
  1217. battclockPrivate2()()
  1218. ##end
  1219.  
  1220. */
  1221. //-------------------------------------------------------------------------
  1222. void find_function_info(void) {
  1223.  
  1224. struct FileCache *fc;
  1225. char *fname;
  1226. int i;
  1227.  
  1228.     // Find out how many .fd files in FD: directory
  1229.     num_fdfiles = calc_num_fd_files();
  1230.     if (VERBOSE) printf("FD: directory contains %d libraries.\n", num_fdfiles);
  1231.  
  1232.     if (num_fdfiles > MAX_LIBS) {
  1233.         printf("Your FD: Directory contains too many entries for HeartBeat (%d > %d)\n",
  1234.             num_fdfiles, MAX_LIBS);
  1235.         cleanup();
  1236.     }
  1237.  
  1238.     // Move to FD: directory so we can use short relative filanemes.
  1239.     chdir("FD:");
  1240.  
  1241.     fc = fd_caches;                        // starting from 1st .fd file
  1242.     fname = FdDirCache.filebuf;
  1243.     total_funcs = libnum = 0;            // starting from library array slot #0
  1244.  
  1245.     for (i=0; i< num_fdfiles; i++) {
  1246.         if (!load_file(fname, fc)) {
  1247.             if (VERBOSE) printf("Couldn't cache %s !\n", fname);
  1248.             cleanup();
  1249.         }
  1250.         fc->filename = fname;            // store name of cached file
  1251.  
  1252.         // parse .FD file and extract all function call information
  1253.         if (!process_fd_file(fc)) {
  1254.             if (VERBOSE) printf("File %s couldn't be parsed.\n", fc->filename);
  1255.         } else {
  1256.             libnum++;                    // done one more library...
  1257.         }
  1258.  
  1259.         fc++;                            // point to next file cache
  1260.         fname += 1+ strlen(fname);        // point to next .fd filename
  1261.     }
  1262.  
  1263.     if (VERBOSE)
  1264.         printf("Counted %d functions in %d libraries\n", total_funcs, libnum);
  1265.  
  1266.     // from now on, the remainder of the node pool is used to allocate
  1267.     // function contexts. (node_pool is used to reset the ctxt_pool ptr).
  1268.     ctxt_pool = (void*) node_pool;
  1269.  
  1270.  
  1271.     // set the library array index ceiling
  1272.     numlibs = libnum;
  1273. }
  1274. //-------------------------------------------------------------------------
  1275. // Find howmany .fd files there are in the FD: directory.
  1276. //-------------------------------------------------------------------------
  1277. int calc_num_fd_files( void ) {
  1278.  
  1279. int match;
  1280. char *matchptr;        // ptr to be filled in by stcpm()
  1281. register int lines;
  1282. register char * ptr;
  1283. BOOL ret;
  1284.                                         // Let "LIST" do all the hard work.
  1285.     ret = Execute("C:LIST >T:FDLIST FD:#?.fd nohead quick",0,0);
  1286.     if (!ret) {
  1287.         printf("Could not 'LIST' your FD: directory.\n");
  1288.         cleanup();
  1289.     }
  1290.                                         // Let "SORT" do some more hard work.
  1291.     ret = Execute("C:SORT T:FDLIST TO T:FDL2",0,0);
  1292.     if (!ret) {
  1293.         printf("Could not 'SORT' filenames.\n");
  1294.         cleanup();
  1295.     }
  1296.  
  1297.     if (! load_file("T:FDL2", &FdDirCache)) {
  1298.         printf("Failed to load LIST output 'T:FDL2'\n");
  1299.         cleanup();
  1300.     }
  1301.  
  1302.     ptr = FdDirCache.filebuf;            // go analyze LIST's output.
  1303.     lines = 0;
  1304.     while (*ptr) {                        // while not EOF
  1305.         if (*ptr++ == LF) {                // count lines
  1306.             lines++;
  1307.         }
  1308.     }
  1309.  
  1310.     // Turn filename list into list of C-strings
  1311.     text_to_heap (&FdDirCache);
  1312.  
  1313.     // Now check first line and make sure it contains the substring ".fd"
  1314.     // If not, then list probably printed an error message, so we quit.
  1315.     // do an unanchored pattern match (Lattice function)
  1316.  
  1317.     ptr = FdDirCache.filebuf;
  1318.     match = stcpm(ptr, ".fd",&matchptr);
  1319.  
  1320.     if (!match) {
  1321.         printf("LIST of FD: directory failed.\n");
  1322.         cleanup();
  1323.     }
  1324.  
  1325.     // if LIST went OK then # of lines == # of .fd files
  1326.     return lines;
  1327. }
  1328. //-------------------------------------------------------------------------
  1329. // User just clicked the currently highlighted system function name.
  1330. // Add this system call to the list of traced ones and stretch Monitoring
  1331. // window to hold extra function line.
  1332. //
  1333. // return FALSE if we can't accept any more functions.
  1334. //-------------------------------------------------------------------------
  1335.  
  1336. BOOL add_function (struct SysCall *syscall) {
  1337.  
  1338. char addr_str[]="$0000FFFF   ";        // output buf for bin2hex conversion
  1339. short oldheight;
  1340. struct NewWindow *NW;
  1341. struct Context *cx;
  1342. register USHORT *wedge,*code;
  1343. APTR newpatch;
  1344. int dy,len;
  1345. register int i;
  1346.  
  1347.     if (syscall->ctxt) return TRUE;            // don't bother patching same func twice!!
  1348.  
  1349.     if (monitored == MAX_PATCHED) return FALSE;    // or exceeding max number
  1350.  
  1351.         // If function call is the very first one and Window therefore does
  1352.         // not exist yet, create it first.
  1353.  
  1354.     if (!monitored) {
  1355.  
  1356.         NW = &nw;
  1357.         NW->Title    = "Monitored Functions";
  1358.         NW->TopEdge = 30; NW->LeftEdge = 640-380;
  1359.         NW->Width    = PANE_X+48*CHAR_WIDTH; NW->Height = 27;
  1360.         NW->Flags    = WFLG_CLOSEGADGET|
  1361.                       WFLG_DEPTHGADGET|
  1362.                       WFLG_REPORTMOUSE|
  1363.                       WFLG_DRAGBAR;
  1364.  
  1365.         monwindow = OpenWindow(NW); if (!monwindow) return FALSE;
  1366.  
  1367.         monwindow->UserPort = IDCMPport;        // share global event MsgPort
  1368.         ModifyIDCMP(monwindow, IDCMP_SELECTION); // allow events from new window
  1369.  
  1370.         monrp = monwindow->RPort;
  1371.  
  1372.         Move (monrp, PANE_X, PANE_Y+6);
  1373.         SetDrMd(monrp, JAM1); SetAPen(monrp, 1);
  1374.         //Text (monrp, "   Called    Matched  Function", 30);
  1375.         //             "$0000FFFF  $0000FFFF  SuperVisor"
  1376.  
  1377.         Text (monrp,   " Called Matched   Address  Function", 35);
  1378.         //               "$00FFFF $00FFFF $07FFFFFF  SuperVisor"
  1379.  
  1380.         Move (monrp, PANE_X, PANE_Y+8);
  1381.         Draw (monrp, PANE_X+35*CHAR_WIDTH , PANE_Y+8);
  1382.     }
  1383.  
  1384.     oldheight = monwindow->Height;
  1385.     SizeWindow(monwindow, 0, CHAR_HEIGHT);
  1386.     Delay(7);    // Wait for Intuition to actually do the async sizing
  1387.  
  1388.         // Check that window actually stretched correctly.
  1389.         // If it didn't (coz window's touching bottom of Workbench) then
  1390.         // move window up and try again (If it fails again: quit)
  1391.  
  1392.     dy = monwindow->Height - oldheight;
  1393.     if (dy != CHAR_HEIGHT) {
  1394.         oldheight = monwindow->Height;
  1395.         MoveWindow(monwindow, 0, -(CHAR_HEIGHT-dy));
  1396.         SizeWindow(monwindow, 0, CHAR_HEIGHT-dy);
  1397.         Delay(7);
  1398.         if (oldheight != (monwindow->Height -(CHAR_HEIGHT-dy))) return FALSE;
  1399.     }
  1400.  
  1401. // OK. At this point we can definitely patch this function.
  1402. // Print function information in window. (previous Function address printing
  1403. // is done lower down after SetFunction() )
  1404.  
  1405.     SetDrMd(monrp, JAM1); SetAPen(monrp, 1);
  1406.     Move(monrp, PANE_X + (27*CHAR_WIDTH), PANE_Y +10 + (monitored+1) * CHAR_HEIGHT);
  1407.     Text(monrp, syscall->funcname, syscall->namelen);
  1408.  
  1409.     
  1410.     patched_calls[monitored++] = syscall; // track call in array of patched ones
  1411.  
  1412.     cx = ctxt_pool++;                        // allocate a Context
  1413.  
  1414.     if ( ((char*)ctxt_pool) > ((char*)pool_base)+POOL_SIZE-200)
  1415.         printf("About to blow pool ! **BUG**\n");
  1416.  
  1417.     init_context(cx);                        // fill in regs, zero counters
  1418.     syscall->ctxt = cx;                        // give SysCall struct a Context
  1419.  
  1420.     wedge = (USHORT*) ctxt_pool;            // spot for wedge code
  1421.     newpatch = (APTR) wedge;                // remember start address
  1422.  
  1423.     code = (USHORT*) WEDGE;                    // R/O image of wedge code
  1424.     i = *(code-1);                            // is this many WORDs long
  1425.     while (i--) {
  1426.         *wedge++ = *code++;                    // Copy wedge routine
  1427.     }
  1428.     ctxt_pool = (struct Context*) wedge;    // update free memory ptr
  1429.  
  1430.     // Now patch library and fill in normal func address and counter address
  1431.     // in patch.
  1432.     
  1433.     Disable();
  1434.  
  1435.     cx->stdvector = SetFunction(syscall->parent_lib, syscall->func_LVO, newpatch);
  1436.  
  1437. #define    patch_wedge(wedge,offs,patch)    \
  1438.     *((ULONG*)((wedge)+ *(((UWORD*)WEDGE)-offs))) = (ULONG)patch;
  1439.  
  1440.     patch_wedge((UWORD*)newpatch, 2, cx->stdvector);    // JMP CHAIN
  1441.     patch_wedge((UWORD*)newpatch, 3, &cx->trapped_cnt);    // MATCH CNT
  1442.     patch_wedge((UWORD*)newpatch, 4, &cx->called_cnt);    // NORM CNT
  1443.     patch_wedge((UWORD*)newpatch, 5, cx);                // CTXT PTR
  1444.  
  1445.     Enable();
  1446.  
  1447.     // generate hex string of function code start address
  1448.     len = stcl_h(addr_str+1, (long) cx->stdvector);
  1449.  
  1450.     Move(monrp, PANE_X + ((24-len)*CHAR_WIDTH), PANE_Y +10 + monitored*CHAR_HEIGHT);
  1451.     Text(monrp, addr_str, len+1);
  1452.  
  1453.     return TRUE;        // function successfully added to list
  1454. }
  1455. //-------------------------------------------------------------------------
  1456. // Initialize a Context structure.
  1457. // Fill registers with a no-match template and clear counters.
  1458. //-------------------------------------------------------------------------
  1459. void init_context( struct Context *cx) {
  1460.  
  1461. register int i;
  1462.  
  1463.     // D0 and A7 get special values to get fastest possible "no match"
  1464.  
  1465.     cx->regvals[0] = 0xA1B2C3D4;    cx->regvals[15] = 0x00000000;
  1466.     cx->regmasks[0]= 0xFFFFFFFF;    cx->regmasks[15]= 0xFFFFFFFF;
  1467.  
  1468.     for (i=1; i<15; i++) {                    // skipping D0 and A7 itself
  1469.         cx->regvals[i] = 0;                    // clear interface regs
  1470.         cx->regmasks[i] = 0;
  1471.     }
  1472.  
  1473.     cx->freeze = cx->frozen = FALSE;        // don't freeze on match
  1474.     cx->called_cnt = cx->trapped_cnt = 0;    // clear counters
  1475.     cx->last_called_cnt = cx->last_trapped_cnt = -1;    // force first update
  1476. }
  1477. //-------------------------------------------------------------------------
  1478. // For all patched system functions, see if their call frequency counters
  1479. // have changed since last time and if so re-print them.
  1480. //-------------------------------------------------------------------------
  1481.  
  1482. void refresh_counters(void) {
  1483.  
  1484. char counter_str[]="$0000FFFF   ";        // output buf for bin2hex conversion
  1485. register struct Context *cx;
  1486. struct SysCall **syscall;
  1487. UBYTE oldmask;
  1488. int i;
  1489. register int len;
  1490.  
  1491.     if (!monwindow) return;                // update monitor window if it exists
  1492.  
  1493.     oldmask = monrp->Mask; monrp->Mask = 1;            // write counters in plane 1 only
  1494.  
  1495.     SetDrMd(monrp, JAM2); SetAPen(monrp, 1);        // overwrite mode
  1496.  
  1497.     syscall = patched_calls;            // point to array of SysCall ptrs
  1498.     for(i=1; i <= monitored; i++) {        // for all monitored funcs DO...
  1499.         cx = (*syscall)->ctxt;
  1500.  
  1501.         if (cx->called_cnt != cx->last_called_cnt) {        // if counter changed
  1502.             cx->last_called_cnt = cx->called_cnt;            // old = new
  1503.             len = stcl_h(counter_str+1, cx->called_cnt);    // gen hex
  1504.             len = len > 6 ? 6 : len;
  1505.  
  1506.             Move(monrp, PANE_X + (6-len)*CHAR_WIDTH, PANE_Y+10 + i*CHAR_HEIGHT);
  1507.             Text(monrp, counter_str, len+1);                // print counter
  1508.         }
  1509.  
  1510.         if (cx->trapped_cnt != cx->last_trapped_cnt) {
  1511.             cx->last_trapped_cnt = cx->trapped_cnt;
  1512.             len = stcl_h(counter_str+1, cx->trapped_cnt);
  1513.             len = len > 6 ? 6 : len;
  1514.  
  1515.             Move(monrp, PANE_X + ((8+6)-len)*CHAR_WIDTH, PANE_Y+10 + i*CHAR_HEIGHT);
  1516.             Text(monrp, counter_str, len+1);                // print counter
  1517.         }
  1518.  
  1519.         Move(monrp, PANE_X + (26*CHAR_WIDTH), PANE_Y+10 +i*CHAR_HEIGHT);
  1520.         if (cx->freeze) {
  1521.             if (cx->frozen) {
  1522.                 Text(monrp, "*", 1);
  1523.             } else {
  1524.                 Text(monrp, "!", 1);
  1525.             }
  1526.         } else {
  1527.             Text(monrp, " ", 1);
  1528.         }
  1529.  
  1530.         syscall++;                        // goto next SysCall structure
  1531.     }
  1532.     monrp->Mask = oldmask;                // restore normal bitplane writing mask
  1533. }
  1534. //-------------------------------------------------------------------------
  1535. // User has switched call tracking mode (global <-> Task only)
  1536. // so reset all call counters to start off with clean statistics
  1537. //-------------------------------------------------------------------------
  1538.  
  1539. void reset_counters(void) {
  1540.  
  1541. struct library *lib;
  1542. register struct SysCall *syscall;
  1543. UBYTE oldmask;
  1544.  
  1545.     if (monitored) {                            // clear old counter strings
  1546.         
  1547.         if (!monwindow) printf("BUG in reset_counters!\n");
  1548.  
  1549.         oldmask = monrp->Mask; monrp->Mask = 1;    // Affect 1st bitplane only
  1550.         SetAPen(monrp, 0);
  1551.         RectFill(monrp, PANE_X, PANE_Y+12,
  1552.                         PANE_X+ 15*CHAR_WIDTH -1, PANE_Y+12+ monitored * CHAR_HEIGHT);
  1553.         monrp->Mask = oldmask;                    // restore normal bitplane mask
  1554.     }
  1555.  
  1556.     for (libnum=0; libnum<numlibs; libnum++) {
  1557.         if (libs[libnum].openhandle) {            // only if library valid
  1558.             lib = &libs[libnum];
  1559.             syscall = (struct SysCall*) lib->funcslist.lh_Head;
  1560.             while (syscall->func_node.ln_Succ) {
  1561.                 if (syscall->ctxt) {    // only patched functions have counters...
  1562.                     init_context(syscall->ctxt);
  1563.                 }
  1564.                 syscall = (struct SysCall*) syscall->func_node.ln_Succ;
  1565.  
  1566.             }    // while functions in library
  1567.         }        // if valid library
  1568.     }            // for all slots in libs array
  1569. }
  1570. //-------------------------------------------------------------------------
  1571. // Highlight a rectangle at BOX coordinates x,y that's width wide.
  1572. //-------------------------------------------------------------------------
  1573. void fill_box( int x, int y, int yoffs, int width, struct RastPort *rp, int pen) {
  1574.  
  1575. int ulx,uly;
  1576. UBYTE oldmask;
  1577.  
  1578.     ulx = PANE_X + x * MAX_LABLEN*CHAR_WIDTH;
  1579.     uly = PANE_Y + yoffs+ y * CHAR_HEIGHT;
  1580.  
  1581.     SetDrMd(rp, JAM1); SetAPen(rp, pen);
  1582.     oldmask = rp->Mask; rp->Mask = 2;        // Affect 2nd bitplane only
  1583.  
  1584.     RectFill(rp, ulx, uly, ulx+width, uly+CHAR_HEIGHT-1);
  1585.  
  1586.     rp->Mask = oldmask;                        // restore normal bitplane mask
  1587. //-------------------------------------------------------------------------
  1588. // Analyze a cached .fd file and extract system call information.
  1589. // Open the Library/Device/Resource of this file to get a firm grip on object.
  1590. //-------------------------------------------------------------------------
  1591.  
  1592. BOOL process_fd_file    (struct FileCache *fc) {
  1593.  
  1594. struct SysCall *funky;                // a ptr to a new System Call "node"
  1595. struct Node *object=NULL;
  1596. char *endquote,*endfunc;
  1597. char *objtype,*newptr;
  1598. register char *ptr;                    // .fd file text scanning ptr
  1599. BOOL skip_private = FALSE;            // skip functions which are system private
  1600. int scan_state = NEED_NAME;            // starting scanning state
  1601. int bias = -6;                        // default starting LVO
  1602.  
  1603.     libs[libnum].numfuncs = 0;        // init # of functions for this library
  1604.     NewList (&libs[libnum].funcslist);
  1605.  
  1606.     ptr = fc->filebuf;                // starting from beginning of cached .fd file
  1607.  
  1608.     while (*ptr) {                    // while not EOF
  1609.         switch (scan_state) {
  1610.  
  1611.             //-----------------------------------------------------------------
  1612.             case NEED_NAME:
  1613.                 if (*ptr++ != '*') return FALSE;
  1614.                 if (*ptr++ != ' ') return FALSE;
  1615.                 if (*ptr++ != '"') return FALSE;
  1616.                 endquote = strchr(ptr, '"');    // find end of quoted str
  1617.                 if (!endquote) return FALSE;
  1618.  
  1619.                 *endquote++ = '\0';                // turn quoted string into C-string
  1620.                 libs[libnum].libname = ptr;
  1621.                 strlwr(ptr);                    // convert name to lower case
  1622.                 objtype = strchr(ptr,'.');        // find what type of "library"
  1623.  
  1624.                 if (FORCEOPEN) {
  1625.                     printf("Forced open option not implemented yet.\n");
  1626. //                    switch (*(objtype+1)) {
  1627. //                        case 'l':    object = OpenLibrary(ptr); break;
  1628. //    **!!                case 'd':    object = OpenDevice(ptr); break;
  1629. //                        case 'r':    object = OpenResource(ptr); break;
  1630. //                    }
  1631. //                } else {
  1632.  
  1633.                 } {
  1634.                     Forbid();
  1635.                         switch (*(objtype+1)) {
  1636.                             case 'l': // LIBRARY
  1637.                                 object = FindName(&SysBase->LibList, ptr); break;
  1638.                             case 'd': // DEVICE
  1639.                                 object = FindName(&SysBase->DeviceList, ptr); break;
  1640.                             case 'r': // RESOURCE
  1641.                                 object = FindName(&SysBase->ResourceList, ptr); break;
  1642.                         }
  1643.  
  1644.             // Make referenced object unswappable by bumping its Use counter !
  1645.  
  1646.  
  1647.                         if (object)    ((struct Library*)object)->lib_OpenCnt++;
  1648.                     Permit();
  1649.                 }
  1650.  
  1651.                 if (!object) {
  1652.                     if (VERBOSE) printf("Object '%s' not available in memory.\n", ptr);
  1653.                     return FALSE;
  1654.                 }
  1655.                 else libs[libnum].openhandle = (struct Library *) object;
  1656.  
  1657.                 ptr = endquote;                    // goto next line;
  1658.                 scan_state = NEUTRAL;
  1659.                 break;
  1660.  
  1661.             //-----------------------------------------------------------------
  1662.             case NEUTRAL:
  1663.  
  1664.                 if (*(ptr-1) != LF) {            // goto new line if not on bound
  1665.                     ptr = 1+ strchr(ptr, LF);
  1666.                 };
  1667.  
  1668.                 switch (*ptr) {                    // determine which line type
  1669.                     case '#':                    // this is and switch state
  1670.                         scan_state = GET_COMMAND;    // accordingly
  1671.                         break;
  1672.  
  1673.                     case '*':
  1674.                         ptr++;
  1675.                         scan_state = NEUTRAL; break;
  1676.  
  1677.                     default:
  1678.                         scan_state = GET_FUNC; break;
  1679.                 }
  1680.                 break;
  1681.  
  1682.             //-----------------------------------------------------------------
  1683.             case GET_FUNC:
  1684.  
  1685.  
  1686.                 if (skip_private) {            // don't collect system private
  1687.                     ptr++;                    // calls
  1688.                     bias += 6;                // keep track of LVO though...
  1689.                     scan_state = NEUTRAL;
  1690.                     break;
  1691.                 }
  1692.  
  1693.                 endfunc = strchr(ptr, '(');    // find '('
  1694.                 *endfunc = '\0';            // turn func name into C-string
  1695.  
  1696.                 funky = node_pool++;        // allocate a new function node
  1697.  
  1698.                 funky->funcname    = ptr;        // fill in name related info
  1699.                 funky->namelen    = endfunc - ptr;
  1700.                 funky->func_LVO    = -bias;    // fill in its _LVO value
  1701.                 funky->ctxt        = NULL;        // not patched yet...
  1702.                 funky->parent_lib= libs[libnum].openhandle;    // link func to lib
  1703.  
  1704.                 AddTail(&libs[libnum].funcslist, (struct Node *)funky);
  1705.  
  1706.                 libs[libnum].numfuncs++;    // track how many functions on list
  1707.                 total_funcs++;                // and stored in total
  1708.  
  1709.                 if (VERBOSE) printf("FUNCTION: %s,\tLVO=-%d\n", ptr, bias);
  1710.  
  1711.                 ptr = 1 + endfunc;            // point past \0 !
  1712.                 bias += 6;                    // keep track of LVO
  1713.  
  1714.                 scan_state = NEUTRAL;
  1715.                 break;
  1716.  
  1717.             //-----------------------------------------------------------------
  1718.             case GET_COMMAND:
  1719.                 ptr++;
  1720.                 if (*ptr++ != '#') return FALSE;
  1721.  
  1722.                 switch (*ptr++) {
  1723.                     case 'b':
  1724.                         if (*ptr == 'i') {            // ##bias
  1725.                             ptr += 3;
  1726.                             bias = strtol(ptr, &newptr, 10);    // get new bias
  1727.                         } else if (*ptr == 'a')    {    // ##base
  1728.                             // name of library base command is skipped
  1729.                         }
  1730.                         break;
  1731.  
  1732.                     case 'e':                        // ##end
  1733.                         ptr = "";    break;            // end the scanning
  1734.  
  1735.                     case 'p':
  1736.                         if (*ptr == 'u') {            // ##public
  1737.                             ptr += 5;
  1738.                             skip_private = FALSE;
  1739.                         } else if (*ptr == 'r')    {    // ##private
  1740.                             ptr += 6;
  1741.                             skip_private = TRUE;
  1742.                         }
  1743.                         break;
  1744.                 }
  1745.                 scan_state = NEUTRAL;
  1746.                 break;
  1747.  
  1748.             //-----------------------------------------------------------------
  1749.         }    // switch (scan_state)
  1750.     }        // while (*ptr)
  1751.  
  1752.     return TRUE;            // Parsed entire .fd file without problems
  1753. }
  1754. //-------------------------------------------------------------------------
  1755. // Open main HeartBeat window (but finish off its menustrip first).
  1756. //-------------------------------------------------------------------------
  1757.  
  1758. BOOL popup_funcwindow (void) {
  1759.  
  1760.     nw.LeftEdge = (screen->Width - nw.Width) /2;    // center window on screen
  1761.  
  1762.     if (!(window = OpenWindow(&nw)))        // Open function selection window
  1763.         return FALSE;                        // WITHOUT IDCMP flags
  1764.  
  1765.     window->UserPort = IDCMPport;            // use global Intuition event MsgPort
  1766.  
  1767.     rp = window->RPort;                        // grab this window's RastPort ptr
  1768.  
  1769.     append_lib_menus();                        // Construct NewMenu array
  1770.  
  1771.     menustrip = CreateMenus(mymenus, TAG_DONE);    // Create MenuStrip
  1772.     if (!menustrip) return FALSE;            // if failed to alloc mem for it...
  1773.  
  1774.     LayoutMenus(menustrip, vi, TAG_DONE);    // Position Menus & Items
  1775.  
  1776.     SetMenuStrip(window, menustrip);        // Attach menu to window
  1777.     OffMenu(window, FULLMENUNUM(OPTIONS_MENU,NOITEM,NOSUB));    // disable menu
  1778.     menus_exist = TRUE;
  1779.  
  1780.     ModifyIDCMP(window, IDCMP_SELECTION);    // tell Intuition to start sending
  1781.  
  1782.     return TRUE;
  1783. }
  1784. //-------------------------------------------------------------------------
  1785. // Part of the MenuStrip is dynamically generated at init time from the
  1786. // list of .fd files we found in the FD: directory.
  1787. // Here we finish off the rest of the array of NewMenu structs.
  1788. //
  1789. // Since we can have a very long list of libraries we have two menus which
  1790. // cope with the two alphabetical groups starting A-I and J-Z.
  1791. //-------------------------------------------------------------------------
  1792.  
  1793. void append_lib_menus(void){
  1794.  
  1795. int i;
  1796. struct NewMenu *newmenu;
  1797.  
  1798.     lowlibs = 0;                    // count how many are in first menu
  1799.     newmenu = mymenus + NEWMENU_APPEND;    // point at the first empty slot
  1800.  
  1801.     for (i=0; i<numlibs; i++) {        // if lib name starts with A..I
  1802.         if (toupper(libs[i].libname[0]) <= 'I') {    // and .fd file was
  1803.             if (libs[i].numfuncs) {                    // parsed succesfully
  1804.                 newmenu->nm_Type    = NM_ITEM;
  1805.                 newmenu->nm_Label    = libs[i].libname;
  1806.                 newmenu->nm_CommKey    = NULL;
  1807.                 newmenu->nm_Flags    = 0;
  1808.                 newmenu->nm_MutualExclude = 0L;
  1809.                 newmenu++;
  1810.                 lowlibs++;
  1811.             }
  1812.         }
  1813.     }
  1814.  
  1815. // Now construct the Menu for Libraries J-Z.
  1816.  
  1817.     newmenu->nm_Type    = NM_TITLE;    // Insert a MENU TITLE for 2nd Libraries
  1818.     newmenu->nm_Label    = "Libraries J-Z";
  1819.     newmenu->nm_CommKey    = NULL;
  1820.     newmenu->nm_Flags    = 0;
  1821.     newmenu->nm_MutualExclude = 0L;
  1822.  
  1823.     newmenu++;                        // and group all other libraries under 2nd
  1824.  
  1825.     for (i=0; i<numlibs; i++) {
  1826.         if (toupper(libs[i].libname[0]) >= 'J') {
  1827.             if (libs[i].numfuncs) {
  1828.                 newmenu->nm_Type    = NM_ITEM;
  1829.                 newmenu->nm_Label    = libs[i].libname;
  1830.                 newmenu->nm_CommKey    = NULL;
  1831.                 newmenu->nm_Flags    = 0;
  1832.                 newmenu->nm_MutualExclude = 0L;
  1833.                 newmenu++;
  1834.             }
  1835.         }
  1836.     }
  1837.  
  1838. // Add final end marker.
  1839.  
  1840.     newmenu->nm_Type    = NM_END;    // Terminate NewMenu array with the required
  1841.     newmenu->nm_Label    = NULL;        // end marker
  1842.     newmenu->nm_CommKey    = NULL;
  1843.     newmenu->nm_Flags    = 0;
  1844.     newmenu->nm_MutualExclude = 0L;
  1845. }
  1846.  
  1847. //-------------------------------------------------------------------------
  1848. struct taskinfo {            // struct is private to ask_task(), get_task_sel()
  1849.     struct Node ti_node;
  1850.     struct Task *ti_Task;    // ptr to Task for when we get selection
  1851.     char   taskname[8+2+MAX_TASKLAB];    // 8 chars for hex Task ptr and N for name itself
  1852. };
  1853.  
  1854. //-------------------------------------------------------------------------
  1855. // User wants to change which Task he's snooping on.
  1856. //
  1857. // Traverse system Task lists and construct a local (static) list of Tasks
  1858. // with their names and hex TCB addresses for a LISTVIEW gadget to display.
  1859. // Open a window with this LISTVIEW and two more "USE", "CANCEL" gadgets.
  1860. // Don't wait for an answer here. Return immediately. Main loop will handle
  1861. // selection and the closing of this window.
  1862. //-------------------------------------------------------------------------
  1863.  
  1864. BOOL ask_task (char *wintitle) {
  1865.  
  1866. static struct TagItem ListViewTags[] =    {
  1867.     GTLV_Labels, NULL,                // filled in with &taskList
  1868.     GTLV_Top, 0,
  1869.     LAYOUTA_SPACING, 1,
  1870.     GTLV_ShowSelected, NULL,        // add read-only label showing selected item
  1871.     GTLV_Selected, 0,
  1872.     GTLV_ScrollWidth, 16,            // width of scroll bar
  1873.     TAG_DONE
  1874. };
  1875.  
  1876. struct NewGadget ng = {                // Not static coz we want stuff re-initialized
  1877.         PANE_X+3,PANE_Y+2,
  1878.         32*CHAR_WIDTH, 14*CHAR_HEIGHT,
  1879.         "List of Tasks", NULL, NULL,
  1880.         PLACETEXT_BELOW,
  1881.         NULL, NULL
  1882. };
  1883.  
  1884. struct Gadget        *lastgad;
  1885. struct NewWindow    *nW;
  1886.  
  1887.     NewList(&taskList);                    // initialize list header
  1888.  
  1889.     Forbid();                            // freeze view of system lists
  1890.  
  1891.     // accumulate Tasks that are WAITing
  1892.     collect_taskinfo(SysBase->TaskWait.lh_Head);
  1893.  
  1894.     // Also give user access to Tasks which are currently ready to run.
  1895.     // This is very useful since Tasks which crash usually use up their
  1896.     // entire time quantum and therefore are constantly READY.
  1897.  
  1898.     collect_taskinfo(SysBase->TaskReady.lh_Head);
  1899.  
  1900.     Permit();
  1901.  
  1902.     // Now that we've constructed a list of names suitable for a LISTVIEW,
  1903.     // construct gadget and window.
  1904.  
  1905.     ng.ng_VisualInfo = vi;
  1906.     ng.ng_TextAttr     = TAttr;
  1907.     ng.ng_GadgetID     = 0;
  1908.  
  1909.     taskReqGads = NULL; lastgad = CreateContext( &taskReqGads );
  1910.  
  1911.     ListViewTags[0].ti_Data = (ULONG) &taskList;    // pass tasknames to Gadget
  1912.     ng.ng_GadgetID    = 0;
  1913.     lastgad = CreateGadgetA(LISTVIEW_KIND, lastgad, &ng, (struct TagItem *) ListViewTags);
  1914.  
  1915.     // Add "Use" and "Cancel" Gadgets
  1916.  
  1917.     ng.ng_GadgetID++; ng.ng_GadgetText = "Use";
  1918.     ng.ng_Flags        = PLACETEXT_IN;
  1919.     ng.ng_Width        = 7*CHAR_WIDTH;
  1920.     ng.ng_LeftEdge  = 60;
  1921.     ng.ng_TopEdge  += ng.ng_Height + 8;
  1922.     ng.ng_Height    = CHAR_HEIGHT+3;
  1923.     lastgad = CreateGadget(BUTTON_KIND, lastgad, &ng, TAG_DONE);
  1924.  
  1925.     ng.ng_GadgetID++; ng.ng_GadgetText = "Cancel";
  1926.     ng.ng_LeftEdge    = 150;
  1927.               CreateGadget(BUTTON_KIND, lastgad, &ng, TAG_DONE);
  1928.  
  1929.     nW = &nw;
  1930.     nW->Title        = wintitle;
  1931.     nW->TopEdge        = 40;
  1932.     nW->LeftEdge    = 100;
  1933.     nW->Width        = 274;
  1934.     nW->Height        = 150;
  1935.     nW->Flags        = WINDOWCLOSE| ACTIVATE| WINDOWDEPTH| WINDOWDRAG;
  1936.     nW->IDCMPFlags    = 0;
  1937.  
  1938.     taskwindow = OpenWindow(nW);                // open task requester window
  1939.  
  1940.     AddGList(taskwindow, taskReqGads, -1, -1, NULL); // append at end, all gadgets
  1941.     RefreshGList(taskReqGads, taskwindow, NULL, -1); // display new ones
  1942.     GT_RefreshWindow(taskwindow, NULL);
  1943.  
  1944.     taskwindow->UserPort = IDCMPport;            // use global event port
  1945.     ModifyIDCMP(taskwindow, IDCMP_SELECTION);    // enable transmissions
  1946.  
  1947.     app_state = TASKWINDOW; task_num = 0;    // first item is selected by default
  1948.  
  1949.     return TRUE;
  1950. }
  1951. //-------------------------------------------------------------------------
  1952. // Traverse Task/Process list and collect name, TCB addr and CLI num info
  1953. //-------------------------------------------------------------------------
  1954. void collect_taskinfo (struct Node *task) {
  1955.  
  1956. struct taskinfo    *node;
  1957. int len,cli;
  1958.  
  1959.     while (task->ln_Succ) {
  1960.         node = (struct taskinfo*) AllocMem(sizeof (struct taskinfo),MEMF_PUBLIC);
  1961.         node->ti_Task = (struct Task*) task;
  1962.         node->ti_node.ln_Name = node->taskname;
  1963.  
  1964.             // make sure both fields aren't separated by a \0
  1965.         strcpy(node->taskname, "          ");            // pad with spaces
  1966.         len = stcl_h(node->taskname, (int) task);        // print task address
  1967.  
  1968.         stccpy(node->taskname+10, task->ln_Name, MAX_TASKLAB);    // and taskname
  1969.         *(node->taskname + len) = ' ';                    // glue both strings together
  1970.  
  1971.         if (task->ln_Type == NT_PROCESS) {    // If a PROCESS also print CLI num
  1972.             cli = ((struct Process*)task)->pr_TaskNum;
  1973.             if (cli) {                        // only non-zero CLI nums valid
  1974.                 *(node->taskname +8 ) = '0' +cli;
  1975.             }
  1976.         }
  1977.  
  1978.         AddTail(&taskList, (struct Node *) node);
  1979.         task = task->ln_Succ;
  1980.     }
  1981. }
  1982. //-------------------------------------------------------------------------
  1983. // User clicked on CLOSEWINDOW, USE or CANCEL gadget and we have to release
  1984. // our Task information list, gadget memory and window.
  1985. //-------------------------------------------------------------------------
  1986. void kill_taskReq_window(void) {
  1987.  
  1988. struct taskinfo *node,*nodex;
  1989.  
  1990.     node = (struct taskinfo*) taskList.lh_Head;
  1991.     while (nodex = (struct taskinfo*) node->ti_node.ln_Succ) {
  1992.         FreeMem((APTR) node, sizeof (struct taskinfo));
  1993.         node = nodex;
  1994.     }
  1995.  
  1996.     CloseWindowSafely(taskwindow); taskwindow = NULL;
  1997.  
  1998.     FreeGadgets(taskReqGads);                    // free CreateGadget RAM
  1999. }
  2000. //-------------------------------------------------------------------------
  2001. // Find Task # N in our Task information list and point SNOOP_TASK to it.
  2002. //-------------------------------------------------------------------------
  2003. void watch_task(int index) {
  2004.  
  2005. struct taskinfo *node;
  2006.  
  2007.     node = (struct taskinfo*) taskList.lh_Head;
  2008.  
  2009.     while(index--) {
  2010.             // just follow list and find node number N
  2011.         node = (struct taskinfo*) node->ti_node.ln_Succ;
  2012.     }
  2013.  
  2014.     SNOOP_TASK = node->ti_Task;            // set address of Task to be snooped
  2015. }
  2016. //-------------------------------------------------------------------------
  2017. // Pop up the register match window sprinkled with loads of GadTools Gadgets.
  2018. // HeartBeat allows us to monitor functions which get specific arguments.
  2019. // This is done by specifying the contents of the data and address registers
  2020. // when the system function gets called.
  2021. // Masks are used to ignore whole registers or parts of registers.
  2022. // When a function is being traced in this "arguments" mode and the arguments
  2023. // match the template then HeartBeat will either simply increment a counter
  2024. // or FREEZE the calling Task.
  2025. //-------------------------------------------------------------------------
  2026.  
  2027. BOOL ask_register_info (char *wintitle, struct Context *ctxt) {
  2028.  
  2029. int regs;
  2030. char *hexstr="$xxxxyyyy";
  2031. static char *actions[] = {    "Count on match",
  2032.                             "Freeze on match", NULL };
  2033.  
  2034. static char *regnames[] = { "D0","D1","D2","D3","D4","D5","D6","D7",
  2035.                             "A0","A1","A2","A3","A4","A5","A6","A7" };
  2036. struct NewGadget ng = {
  2037.     PANE_X, PANE_Y+12,
  2038.     12*CHAR_WIDTH, CHAR_HEIGHT+4,
  2039.     NULL, NULL, NULL,
  2040.     0,
  2041.     NULL, NULL };
  2042.  
  2043. struct Gadget *lastgad;
  2044. struct NewWindow *nW;
  2045.  
  2046.     ctxt->freeze = ctxt->frozen = FALSE;    // sync up with what Gadget shows!
  2047.  
  2048.     ng.ng_VisualInfo = vi;
  2049.     ng.ng_TextAttr     = TAttr;
  2050.     ng.ng_GadgetID     = 0;
  2051.  
  2052.     regsReqGads = NULL; lastgad = CreateContext( ®sReqGads );
  2053.  
  2054.     // Create 16 String Gadgets. Two per 680x0 register for value and mask.
  2055.  
  2056.     for (regs=0; regs < 16; regs++) {
  2057.         sprintf(hexstr, "$%lX", ctxt->regvals[regs]);
  2058.         ng.ng_Flags            = PLACETEXT_RIGHT;
  2059.         ng.ng_GadgetText    = regnames[regs];
  2060.         lastgad = CreateGadget(STRING_KIND, lastgad, &ng, GTST_String, hexstr, TAG_DONE);
  2061.         
  2062.         sprintf(hexstr, "$%lX", ctxt->regmasks[regs]);
  2063.         ng.ng_GadgetID++;
  2064.         ng.ng_GadgetText    = NULL;
  2065.         ng.ng_Flags            = 0;
  2066.         ng.ng_LeftEdge        += 10*CHAR_WIDTH + 48;
  2067.         lastgad = CreateGadget(STRING_KIND, lastgad, &ng, GTST_String, hexstr, TAG_DONE);
  2068.  
  2069.         ng.ng_LeftEdge -= 10*CHAR_WIDTH + 48;
  2070.         ng.ng_TopEdge  += CHAR_HEIGHT+4 +1;
  2071.         ng.ng_GadgetID++;
  2072.     }
  2073.  
  2074.     // Add Trapping mode (Cycleing) Gadget
  2075.  
  2076.     ng.ng_Flags        = PLACETEXT_IN | NG_HIGHLABEL;
  2077.     ng.ng_Width        = 20*CHAR_WIDTH;
  2078.     ng.ng_LeftEdge  = PANE_X;
  2079.     ng.ng_TopEdge  += 10;
  2080.     lastgad = CreateGadget(CYCLE_KIND, lastgad, &ng, GTCY_Labels, actions, TAG_DONE);
  2081.  
  2082.     // Add "Use" and "Cancel" Gadgets
  2083.  
  2084.     ng.ng_Flags        = PLACETEXT_IN;
  2085.     ng.ng_GadgetID++; ng.ng_GadgetText = "Use";
  2086.     ng.ng_Width        = 7*CHAR_WIDTH;
  2087.     ng.ng_LeftEdge  = 44;
  2088.     ng.ng_TopEdge  += 20;
  2089.     lastgad = CreateGadget(BUTTON_KIND, lastgad, &ng, TAG_DONE);
  2090.  
  2091.     ng.ng_GadgetID++; ng.ng_GadgetText = "Cancel";
  2092.     ng.ng_LeftEdge    += 90;
  2093.     lastgad = CreateGadget(BUTTON_KIND, lastgad, &ng, TAG_DONE);
  2094.  
  2095.     // Open Window for Gadgets to live in
  2096.  
  2097.     nW = &nw;
  2098.     nW->Title = wintitle;
  2099.     nW->TopEdge = 40; nW->LeftEdge = 100;
  2100.     nW->Width = 236; nW->Height = 280;
  2101.     nW->Flags = WINDOWCLOSE| ACTIVATE| WINDOWDEPTH| WINDOWDRAG;
  2102.     nW->IDCMPFlags = 0;
  2103.  
  2104.     regswindow = OpenWindow(nW);        //**!! error
  2105.     regsrp = regswindow->RPort;
  2106.  
  2107.     AddGList(regswindow, regsReqGads, -1, -1, NULL);
  2108.     RefreshGList(regsReqGads, regswindow, NULL, -1);
  2109.     GT_RefreshWindow(regswindow, NULL);
  2110.  
  2111.     Move(regsrp, PANE_X+28, PANE_Y+7);
  2112.     SetAPen(regsrp,1);
  2113.     Text(regsrp,"Values          Masks",20);
  2114.  
  2115.     regswindow->UserPort = IDCMPport;                // use global event port
  2116.     ModifyIDCMP(regswindow, IDCMP_SELECTION);        // enable transmissions
  2117.  
  2118.     app_state = REGSWINDOW;
  2119.  
  2120.     // Add this stage the window sits there with all its Gadgets waiting for
  2121.     // input; but this function returns now, so it's the main event loop that
  2122.     // picks up the user selections and then eventually kills the window
  2123.     // when "Use", "Cancel" or the CLOSEWINDOW Gadget gets selected.
  2124.  
  2125.     return TRUE;
  2126. }
  2127. //-------------------------------------------------------------------------
  2128. // User clicked on CLOSEWINDOW, USE or CANCEL gadget and we have to release
  2129. // our Window and gadget memory.
  2130. //-------------------------------------------------------------------------
  2131. void kill_regsReq_window(void) {
  2132.  
  2133.     CloseWindowSafely(regswindow); regswindow = NULL;
  2134.  
  2135.     FreeGadgets(regsReqGads);                    // free CreateGadget RAM
  2136. }
  2137. //-------------------------------------------------------------------------
  2138. // Turn a cached text file into a collection of C-strings (a heap of strings)
  2139. //-------------------------------------------------------------------------
  2140. void text_to_heap( struct FileCache *fc) {
  2141. register int i;
  2142. register char * ptr;
  2143.  
  2144.     ptr = fc->filebuf;
  2145.  
  2146.     for (i=fc->bufsize; i; i--) {
  2147.         if (*ptr == LF)                // replace all LF chars by string terminators
  2148.             *ptr = '\0';
  2149.         ptr++;
  2150.     }
  2151. }
  2152.  
  2153. //-------------------------------------------------------------------------
  2154. // Turn a LF-terminated string into a proper C-string.
  2155. //-------------------------------------------------------------------------
  2156. void strip_lf (char *str) {
  2157.  
  2158.     while (*str++ != LF)        // go find terminating LF
  2159.         ;
  2160.  
  2161.     *(str-1) = 0;                // and replace by a \0
  2162. }
  2163. //-------------------------------------------------------------------------
  2164. // Close Window safely (taking care of possible queued messages)
  2165. //-------------------------------------------------------------------------
  2166. void CloseWindowSafely( struct Window *win ) {
  2167.     
  2168.     if (win->UserPort) {
  2169.         Forbid();    // we forbid here to keep out of race conditions with Intuition
  2170.  
  2171.             // return any messages for this window that have not yet been processed
  2172.             StripIntuiMessages( win->UserPort, win );
  2173.  
  2174.             win->UserPort = NULL;        // clear UserPort so Intuition will not free it
  2175.             ModifyIDCMP( win, 0L );        // tell inuition to stop sending more messages
  2176.  
  2177.         Permit();                        // turn tasking back on
  2178.     }
  2179.  
  2180.     CloseWindow( win );                // and really close the window
  2181. }
  2182. //-------------------------------------------------------------------------
  2183. // remove and reply to all IntuiMessages on a port that have been sent to a
  2184. // particular window (note that we don't rely on the ln_Succ pointer of a
  2185. // message after we have replied it)
  2186. //-------------------------------------------------------------------------
  2187. void StripIntuiMessages(struct MsgPort *mp, struct Window *win ) {
  2188.  
  2189. register struct IntuiMessage *msg;
  2190. register struct Node *succ;
  2191.  
  2192.     msg = (struct IntuiMessage *) mp->mp_MsgList.lh_Head;    // 1st message
  2193.  
  2194.     while( succ = msg->ExecMessage.mn_Node.ln_Succ ) {
  2195.  
  2196.         if( msg->IDCMPWindow ==  win ) {                    // message addressed
  2197.                                                             // to us ?
  2198.          // Intuition is about to free this message.
  2199.          // Make sure that we have politely sent it back.
  2200.  
  2201.             Remove((struct Node*)msg);
  2202.             ReplyMsg((struct Message*)msg);
  2203.         }
  2204.         
  2205.         msg = (struct IntuiMessage *) succ;        // next IntuiMessage on list
  2206.     }
  2207. }
  2208. //-------------------------------------------------------------------------
  2209. // Open all libraries, initialize arrays, get private memory pool,
  2210. // open two IPC Message Ports (one for timeout messages, one for all Intuition
  2211. // messages), open timer.device, set global function tracking mode.
  2212. //-------------------------------------------------------------------------
  2213.  
  2214. BOOL init_program(void) {
  2215. int i;
  2216.  
  2217.     if (!(AslBase        = (struct AslBase *)      OpenLibrary( "asl.library",0L)))
  2218.         return FALSE;
  2219.     if (!(GadToolsBase  = (struct GadToolsBase *) OpenLibrary( "gadtools.library",0L)))
  2220.         return FALSE;
  2221.     if (!(IntuitionBase = (struct IntuitionBase*) OpenLibrary("intuition.library",0L)))
  2222.         return FALSE;
  2223.     if (!(GfxBase        = (struct GfxBase *)      OpenLibrary( "graphics.library",0L)))
  2224.         return FALSE;
  2225.  
  2226.     screen    = IntuitionBase->ActiveScreen;    // note host Screen
  2227.     TAttr    = screen->Font;                    // note Screen default Font
  2228.     vi        = GetVisualInfo(screen, TAG_DONE);
  2229.  
  2230.     // Mark all file caches as empty
  2231.     FdDirCache.bufsize = 0;
  2232.  
  2233.     for (i=0; i< MAX_LIBS; i++) {
  2234.         fd_caches[i].bufsize = 0;            // all caches are empty
  2235.         libs[i].openhandle     = NULL;        // all libs are unopened
  2236.     }
  2237.  
  2238.     // Mark all patched system call links as invalid
  2239.     monitored = 0;                            // no calls monitored yet..
  2240.     for (i=0; i< MAX_PATCHED; i++) {        // no patched calls yet...
  2241.         patched_calls[i] = NULL;
  2242.     }
  2243.  
  2244.     // Get a large memory pool to hold System Call information
  2245.     pool_base = node_pool = (struct SysCall *) AllocMem(POOL_SIZE, MEMF_PUBLIC|MEMF_CLEAR);
  2246.  
  2247.     if (!pool_base) {
  2248.         printf("Unable to allocate memory pool.\n");
  2249.         return FALSE;
  2250.     }
  2251.  
  2252.     // Create our event message ports
  2253.     if (!(timerport = CreateMsgPort())) return FALSE;
  2254.     if (!(IDCMPport = CreateMsgPort())) return FALSE;
  2255.  
  2256.     if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest*) &timereq, 0)) {
  2257.         printf("Failed to open timer.device\n");
  2258.         return FALSE;
  2259.     }
  2260.  
  2261.     timereq.tr_node.io_Message.mn_ReplyPort = timerport;
  2262.  
  2263.     SNOOP_TASK = NULL;                        // global tracking mode on
  2264.  
  2265.     monwindow = taskwindow = regswindow = NULL;    // no special windows up
  2266.  
  2267.     return TRUE;
  2268. }
  2269. //-------------------------------------------------------------------------
  2270. // Unpatch any patched functions.
  2271. // Unlock resources (Libraries, Devices, Resources)
  2272. // Deallocate all file buffers still in use.
  2273. //-------------------------------------------------------------------------
  2274.  
  2275. void cleanup(void) {
  2276. int i,size;
  2277.  
  2278.     unpatch_functions();
  2279.  
  2280.         // Release all the .FD file caches
  2281.     for (i=0; i< MAX_LIBS; i++) {
  2282.         size = fd_caches[i].bufsize;
  2283.         if (size) {
  2284.             FreeMem(fd_caches[i].filebuf, size);
  2285.         }
  2286.     }
  2287.  
  2288.     size = FdDirCache.bufsize;
  2289.     if (size)
  2290.          FreeMem(FdDirCache.filebuf, size);
  2291.  
  2292.         // Release all the libraries/devices/resources which we locked
  2293.     for (libnum=0; libnum<numlibs; libnum++) {
  2294.         if (libs[libnum].openhandle)
  2295.             libs[libnum].openhandle->lib_OpenCnt--;
  2296.     }
  2297.  
  2298.         // Free all SysCall structures (pool)
  2299.     if (pool_base)
  2300.         FreeMem((char*)pool_base, POOL_SIZE);
  2301.  
  2302.     if (IntuitionBase) {
  2303.         if (window) {
  2304.             window->UserPort = NULL;    // Intuition: leave MY port alone!
  2305.             if (menus_exist) {
  2306.                 ClearMenuStrip(window);
  2307.                 FreeMenus(menustrip);
  2308.             }
  2309.             CloseWindowSafely(window);
  2310.         }
  2311.         FreeVisualInfo(vi);
  2312.         CloseLibrary( (struct Library *) IntuitionBase);
  2313.     }
  2314.  
  2315.     if (AslBase) {
  2316.         CloseLibrary( (struct Library *) AslBase);
  2317.     }
  2318.  
  2319.     if (GadToolsBase) {
  2320.         CloseLibrary( (struct Library *) GadToolsBase);
  2321.     }
  2322.  
  2323.     if (GfxBase)      {
  2324.         CloseLibrary( (struct Library *) GfxBase);
  2325.     }
  2326.  
  2327.     if (timerport) DeleteMsgPort((struct MsgPort*)timerport);
  2328.     if (IDCMPport) DeleteMsgPort((struct MsgPort*)IDCMPport);
  2329.  
  2330.     CloseDevice((struct IORequest*) &timereq);
  2331.  
  2332.     exit(0);
  2333. }
  2334. //-------------------------------------------------------------------------
  2335. // For all functions which we've patched to track their use, undo all.
  2336. //-------------------------------------------------------------------------
  2337.  
  2338. void unpatch_functions(void) {
  2339.  
  2340. int i;
  2341. struct SysCall *syscall;
  2342.  
  2343.     if (!monitored) return;            // if nothing to unpatch... don't
  2344.  
  2345.     // Unpatch all functions which HeartBeat patched.
  2346.  
  2347.     for (i=0; i<monitored; i++) {
  2348.  
  2349.         syscall = patched_calls[i];
  2350.         if (VERBOSE) printf("Unpatching Call %s, %x \n",
  2351.                          syscall->funcname, syscall->ctxt->stdvector);
  2352.  
  2353.         SetFunction(syscall->parent_lib, syscall->func_LVO, syscall->ctxt->stdvector );
  2354.         syscall->ctxt = NULL;
  2355.     }
  2356.  
  2357.     ctxt_pool = (void*) node_pool;    // reset Contexts pool ptr
  2358.     monitored = 0;                    // reset # of monitored functions
  2359. }
  2360. //-------------------------------------------------------------------------
  2361.